@redocly/realm 0.135.0-next.3 → 0.135.0-next.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/dist/api-schemas/search-facets.d.ts +41 -0
- package/dist/api-schemas/search-facets.js +1 -0
- package/dist/api-schemas/search.d.ts +66 -0
- package/dist/api-schemas/search.js +1 -0
- package/dist/client/app/Feedback/useSubmitFeedback.js +1 -1
- package/dist/client/app/Sidebar/helpers/filter-out-versioned-items.d.ts +5 -2
- package/dist/client/app/Sidebar/helpers/filter-out-versioned-items.js +1 -1
- package/dist/client/app/UserMenu/useUserMenu.js +1 -1
- package/dist/client/app/pages/DevLogin/DevLogin.js +1 -1
- package/dist/client/app/pages/Invite/Invite.js +1 -1
- package/dist/client/app/search/useAiSearch.js +1 -1
- package/dist/client/app/search/useFacets.js +1 -1
- package/dist/client/app/search/useSearch.js +1 -1
- package/dist/client/app/utils/resolveRouteBySlug.js +1 -1
- package/dist/client/browser-entry.js +2 -2
- package/dist/client/providers/post-message/PostMessageProvider.js +1 -1
- package/dist/client/providers/theme/ThemeDataProvider.js +1 -1
- package/dist/client/templates/asyncapi-docs/template.js +1 -1
- package/dist/client/templates/openapi-docs/helpers.js +2 -2
- package/dist/client/templates/openapi-docs/template.js +1 -1
- package/dist/client/types/post-message.d.ts +4 -0
- package/dist/constants/api.d.ts +49 -0
- package/dist/constants/api.js +1 -0
- package/dist/constants/common.d.ts +0 -48
- package/dist/constants/common.js +1 -1
- package/dist/server/config/env-config.d.ts +2 -2
- package/dist/server/config/env-schema.d.ts +5 -5
- package/dist/server/config/env-schemas/feature-flags.d.ts +4 -0
- package/dist/server/config/env-schemas/feature-flags.js +1 -1
- package/dist/server/config/env-schemas/server-config.d.ts +0 -3
- package/dist/server/config/env-schemas/server-config.js +1 -1
- package/dist/server/constants/common.d.ts +0 -1
- package/dist/server/constants/common.js +1 -1
- package/dist/server/constants/plugins/search.js +1 -1
- package/dist/server/plugins/graphql-docs/template/GraphQLDocs.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/index.js +1 -1
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-gallery.d.ts +4 -0
- package/dist/server/plugins/markdown/attribute-resolvers/resolve-image-gallery.js +1 -0
- package/dist/server/plugins/markdown/extract-frontmatter.d.ts +6 -0
- package/dist/server/plugins/markdown/extract-frontmatter.js +1 -0
- package/dist/server/plugins/markdown/markdown-frontmatter-loader.js +1 -1
- package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/codemode/build-execute-tool-description.d.ts +4 -0
- package/dist/server/plugins/mcp/docs-mcp/codemode/build-execute-tool-description.js +4 -0
- package/dist/server/plugins/mcp/docs-mcp/codemode/sandbox.d.ts +3 -0
- package/dist/server/plugins/mcp/docs-mcp/codemode/sandbox.js +7 -0
- package/dist/server/plugins/mcp/docs-mcp/codemode/types.d.ts +9 -0
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.d.ts +2 -0
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/search.d.ts +2 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/search.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/core/types.d.ts +6 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/core/types.js +0 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/core/whoami.d.ts +2 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/execute.d.ts +9 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/execute.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-schema.d.ts +2 -3
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type-list.d.ts +2 -9
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/get-graphql-type.d.ts +2 -5
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/list-graphql-apis.d.ts +2 -5
- package/dist/server/plugins/mcp/docs-mcp/tools/graphql/types.d.ts +21 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/index.d.ts +11 -46
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoint-info.d.ts +2 -6
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoints.d.ts +2 -4
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-full-api-description.d.ts +2 -4
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-security-schemes.d.ts +2 -4
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/list-apis.d.ts +2 -5
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.d.ts +16 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/types.js +0 -0
- package/dist/server/plugins/mcp/handlers/errors.js +1 -1
- package/dist/server/plugins/mcp/index.js +1 -1
- package/dist/server/plugins/mcp/mode.d.ts +9 -0
- package/dist/server/plugins/mcp/mode.js +1 -0
- package/dist/server/plugins/mcp/servers/docs-server.js +1 -1
- package/dist/server/plugins/mcp/types.d.ts +1 -0
- package/dist/server/plugins/mcp/workers/execute-mcp-tool.js +1 -1
- package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.d.ts +4 -0
- package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.js +1 -0
- package/dist/server/plugins/search/engines/flexsearch/index.d.ts +3 -3
- package/dist/server/plugins/search/engines/flexsearch/index.js +1 -1
- package/dist/server/plugins/search/engines/search-engine.d.ts +3 -3
- package/dist/server/plugins/search/engines/search-engine.js +1 -1
- package/dist/server/plugins/search/engines/typesense/index.d.ts +3 -3
- package/dist/server/plugins/search/engines/typesense/index.js +1 -1
- package/dist/server/plugins/sitemap/index.js +1 -1
- package/dist/server/types/plugins/common.d.ts +3 -0
- package/dist/server/types/plugins/search.d.ts +2 -2
- package/dist/server/types/web-server.d.ts +8 -0
- package/dist/server/utils/rbac.js +1 -1
- package/dist/server/web-server/auth.js +3 -3
- package/dist/server/web-server/dev-server.js +1 -1
- package/dist/server/web-server/middleware/jsonValidatorMiddleware.d.ts +336 -0
- package/dist/server/web-server/middleware/jsonValidatorMiddleware.js +1 -0
- package/dist/server/web-server/routes/auth.d.ts +1 -1
- package/dist/server/web-server/routes/auth.js +1 -1
- package/dist/server/web-server/routes/catalog/bff-catalog-related-entities.js +1 -1
- package/dist/server/web-server/routes/catalog/bff-catalog.js +1 -1
- package/dist/server/web-server/routes/catalog/catalog-relations.js +1 -1
- package/dist/server/web-server/routes/catalog/catalog.js +1 -1
- package/dist/server/web-server/routes/cors-proxy.js +1 -1
- package/dist/server/web-server/routes/index.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.js +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-routes.js +1 -1
- package/dist/server/web-server/routes/page-data.js +1 -1
- package/dist/server/web-server/routes/search.d.ts +5 -3
- package/dist/server/web-server/routes/search.js +1 -1
- package/dist/types/api.d.ts +15 -0
- package/dist/types/api.js +0 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/utils/auth/build-login-url.js +1 -1
- package/dist/utils/auth/is-auth-route-path.js +1 -1
- package/package.json +14 -12
- package/dist/types/search.d.ts +0 -29
- /package/dist/{types/search.js → server/plugins/mcp/docs-mcp/codemode/types.js} +0 -0
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { McpToolHandler } from '../../../types.js';
|
|
2
|
+
import type { ApiNameVersionArgs } from './types.js';
|
|
2
3
|
declare const _default: {
|
|
3
|
-
'get-security-schemes': McpToolHandler<
|
|
4
|
-
name: string;
|
|
5
|
-
version?: string;
|
|
6
|
-
}>;
|
|
4
|
+
'get-security-schemes': McpToolHandler<ApiNameVersionArgs>;
|
|
7
5
|
};
|
|
8
6
|
export default _default;
|
|
9
7
|
//# sourceMappingURL=get-security-schemes.d.ts.map
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { McpToolHandler } from '../../../types.js';
|
|
2
|
+
import type { ListApisArgs } from './types.js';
|
|
2
3
|
declare const _default: {
|
|
3
|
-
'list-apis': McpToolHandler<
|
|
4
|
-
filter?: string;
|
|
5
|
-
page?: number;
|
|
6
|
-
limit?: number;
|
|
7
|
-
}>;
|
|
4
|
+
'list-apis': McpToolHandler<ListApisArgs>;
|
|
8
5
|
};
|
|
9
6
|
export default _default;
|
|
10
7
|
//# sourceMappingURL=list-apis.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ListApisArgs = {
|
|
2
|
+
filter?: string;
|
|
3
|
+
page?: number;
|
|
4
|
+
limit?: number;
|
|
5
|
+
};
|
|
6
|
+
export type ApiNameVersionArgs = {
|
|
7
|
+
name: string;
|
|
8
|
+
version?: string;
|
|
9
|
+
};
|
|
10
|
+
export type GetEndpointInfoArgs = {
|
|
11
|
+
name: string;
|
|
12
|
+
path: string;
|
|
13
|
+
method: string;
|
|
14
|
+
version?: string;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=types.d.ts.map
|
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetry as c}from"../../../telemetry/index.js";import{McpErrorCodes as o,McpServerType as
|
|
1
|
+
import{telemetry as c}from"../../../telemetry/index.js";import{McpErrorCodes as o,McpServerType as i}from"../constants.js";import{getMcpMode as d}from"../mode.js";class n extends Error{code;data;requestId;constructor(r,t,s,a){super(t),this.name="McpError",this.code=r,this.data=s,this.requestId=a}createErrorResponse(){const r={jsonrpc:"2.0",error:{code:this.code,message:this.message,...this.data?{data:this.data}:{}},id:this.requestId??null},t=u(this.code);return new Response(JSON.stringify(r),{status:t,headers:{"Content-Type":"application/json"}})}}function u(e){switch(e){case o.InvalidRequest:case o.InvalidParams:return 400;case o.MethodNotFound:return 404;case o.ServerError:return 405;case o.InternalError:default:return 500}}function h(e){return new n(o.ServerError,"Method not allowed",void 0,e).createErrorResponse()}function p(e,r=i.Docs,t){const s=e instanceof Error?e.message:String(e),a=e instanceof Error?e.stack:void 0;return c.sendMcpErrorMessage([{id:r,object:"mcpServer",uri:`urn:redocly:realm:mcp:server:${r}`,server_type:r,message:s,stack:a||"",mode:d()}]),new n(o.InternalError,"Internal server error mcp",s,t).createErrorResponse()}function v(e="Invalid request",r){return new n(o.InvalidRequest,e,void 0,r).createErrorResponse()}function I(e="Invalid parameters",r){return new n(o.InvalidParams,e,void 0,r).createErrorResponse()}async function M(e,r,t){try{return await e()}catch(s){return c.sendMcpErrorMessage([{id:r,object:"mcpServer",uri:`urn:redocly:realm:mcp:server:${r}`,server_type:r,message:s?.message||"",stack:s?.stack||"",mode:d()}]),t&&t(),p(s,r)}}export{n as McpError,p as createInternalServerError,I as createInvalidParamsError,v as createInvalidRequestError,h as createMethodNotAllowedError,M as withErrorHandling};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{fileURLToPath as
|
|
1
|
+
import{fileURLToPath as E}from"node:url";import{dirname as O,join as a}from"node:path";import{logger as u}from"../../tools/notifiers/logger.js";import{reporter as R}from"../../tools/notifiers/reporter.js";import{isDefined as q}from"../../../utils/guards/is-defined.js";import{buildGraphqlDescriptions as w,filterIgnoredApiDescriptions as h,getCleanedUpApiDescriptions as A,isMcpInRedirects as T}from"./utils.js";import{isMcpCodeModeEnabled as _}from"./mode.js";import{getDefaultToolSchemas as j,EXECUTE_TOOL_SCHEMA as L}from"./docs-mcp/tool-schemas.js";import{telemetryTraceStep as G}from"../../../cli/telemetry/helpers/trace-step.js";const D="mcp-docs-server-handler",p=O(E(import.meta.url));async function H(){let o=!1;return{id:"mcp",async processContent(e,i){o||await G("build.plugin.mcp",async c=>{const r=await e.loadOpenApiDefinitions(i),d=await e.loadGraphqlDefinitions(i),n=await i.getConfig(),{mcp:t,redirects:v}=n;if(c?.setAttribute("config",JSON.stringify(t||{})),!(t?.hide||t?.docs?.hide)&&(T(v)&&await R.panicOnBuildContentError('The reserved route "/mcp" cannot be used in redirect configuration. Please remove any redirects involving "/mcp" from your redocly.yaml config.'),!t?.docs?.hide)){u.info("Configuring MCP servers...");const C=a(p,"./handlers/docs-mcp-handler.js"),M=A(h(r,t?.docs?.ignore||[])),l=new Map;for(const s of M){const f=s.definition.info?.title||"",g=s.definition.info?.version||"";l.set(`${f.toLowerCase()}@${g}`,{name:f,description:s.definition.info?.description||"",version:g,servers:s.definition.servers||[],relativePath:s.relativePath})}const m=w(h(d,t?.docs?.ignore||[])),P=Object.values(n.products||{}).map(s=>s?.name).filter(q),S=!!n?.access?.requiresLogin,b=n?.access?.rbac||{},y=j({products:P,requiresLogin:S,rbac:b,hasGraphqlApis:m.length>0});e.addMcpTools(a(p,"./docs-mcp/tools/index.js"),y),_()&&e.addMcpTools(a(p,"./docs-mcp/tools/execute.js"),[L]),await I({actions:e,handlerPath:C,apiDescriptionsMap:Object.fromEntries(l),graphqlDescriptions:m,mcpConfig:t}),o=!0}})},async afterRoutesCreated(e,i){const c=await i.getConfig(),{mcp:r}=c;e.setGlobalData({mcpData:{docs:{enabled:!r?.hide&&!r?.docs?.hide,name:r?.docs?.name}}})}}}var z=H;async function I({actions:o,handlerPath:e,apiDescriptionsMap:i,graphqlDescriptions:c,mcpConfig:r}){o.createRequestHandler(D,e),o.addApiRoute({slug:"/mcp",requestHandlerId:D,httpMethod:"all",getStaticData:async()=>({props:{config:{apiDescriptionsMap:i,graphqlDescriptions:c,mcpDocsServerName:r?.docs?.name||"Docs MCP Server"},serverOutDir:o.serverOutDir,tools:o.getMcpTools().map(({importPath:d,...n})=>n)}})}),u.info("Registered Docs MCP Server endpoint at /mcp")}export{D as MCP_DOCS_SERVER_HANDLER_ID,z as default,H as mcpServerPlugin};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { McpMode } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Codemode (a single `execute` tool) is gated by a feature flag, not client config, so
|
|
4
|
+
* only we control the rollout. Kept in its own module so the worker / telemetry path
|
|
5
|
+
* does not pull in the heavier `utils.js` dependencies.
|
|
6
|
+
*/
|
|
7
|
+
export declare function isMcpCodeModeEnabled(): boolean;
|
|
8
|
+
export declare function getMcpMode(): McpMode;
|
|
9
|
+
//# sourceMappingURL=mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{envConfig as o}from"../../config/env-config.js";function e(){return o.REDOCLY_EXP_MCP_CODE_MODE_ENABLED??!1}function t(){return e()?"code":"tools"}export{t as getMcpMode,e as isMcpCodeModeEnabled};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{McpServer as
|
|
1
|
+
import{McpServer as T}from"@redocly/mcp-typescript-sdk/server/mcp.js";import{StreamableHTTPServerTransport as b}from"@redocly/mcp-typescript-sdk/server/streamableHttp.js";import{logger as m}from"../../../tools/notifiers/logger.js";import{mcpToolWorkers as u,MCP_TOOL_WORKER_KEY as _,MCP_TOOL_IS_AVAILABLE_KEY as g}from"../../../workers/mcp-tool-worker-pool.js";import{EXECUTE_TOOL_NAME as i,EXECUTE_TOOL_SCHEMA as I}from"../docs-mcp/tool-schemas.js";import{buildExecuteToolDescription as M}from"../docs-mcp/codemode/build-execute-tool-description.js";import{isMcpCodeModeEnabled as S}from"../mode.js";async function A({name:e,tools:f,context:d}){const a=new T({name:e,version:new Date().toISOString().slice(0,10)},{capabilities:{logging:{}}}),s=new b({sessionIdGenerator:void 0}),n=C(d),c=o=>async(r,t)=>{m.info(`MCP tool called: ${o}`);const E={toolName:o,args:r,context:n,extra:h(t)};return await u.exec(_,[E],{timeout:6e4})},l=async o=>{try{return await u.exec(g,[{toolName:o,context:n}],{timeout:1e4})}catch(r){return m.error(`Failed to check MCP tool availability for "${o}": ${r instanceof Error?r.message:String(r)}`),!1}},p=f.filter(o=>o.name!==i);if(S()){const o=[];for(const r of p)await l(r.name)&&o.push(r);a.tool(i,M(o),I.schema,c(i))}else for(const o of p){const r=o.annotations||{title:o.name},t=a.tool(o.name,o.description,o.schema,r,c(o.name));await l(o.name)||t.disable()}return await a.connect(s),{server:a,transport:s,cleanup:async()=>{s.close()}}}function h(e){return{sessionId:e.sessionId,authInfo:e.authInfo,requestId:e.requestId,requestInfo:e.requestInfo,_meta:e._meta}}function C(e){return{user:e.user,config:e.config,outdir:e.outdir,baseUrl:e.baseUrl,params:e.params,query:e.query,cookies:e.cookies,apiDescriptionsMap:e.apiDescriptionsMap,graphqlDescriptions:e.graphqlDescriptions,products:e.products,accessToken:e.accessToken,metadata:e.metadata}}export{A as createDocsMcpServer};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{telemetry as
|
|
1
|
+
import{telemetry as u}from"../../../telemetry/index.js";import{mcpToolHandlers as p}from"../../../../client/mcp-tool-handlers-entry.js";import{getMcpMode as m}from"../mode.js";import{reportMcpToolCalled as w,reportMcpToolError as f}from"./mcp-tool-telemetry.js";async function b(n){u.initialize();const{toolName:t,args:c,context:o,extra:l}=n,r=m();try{const e=p[t];if(!e)throw new Error(`Unknown MCP tool: ${t}`);const{default:d}=await e(),i=d[t];if(!i)throw new Error(`MCP tool module does not export a handler for "${t}". Expected \`export default { '${t}': handler }\`.`);const a=await(typeof i=="function"?i:i.execute)(c,o,l);if(!x(a))throw new Error(`MCP tool "${t}" returned an invalid result.`);if(a.isError)f(t,a.content.map(({text:s})=>s).join(" "),r);else{const s=a.content.map(({text:h})=>h).join("").length;w(t,r,s)}return a}catch(e){throw f(t,e instanceof Error?e.message:String(e),r,e instanceof Error&&e.stack||""),e}}function x(n){return!n||typeof n!="object"?!1:Array.isArray(n.content)}async function T(n){u.initialize();const{toolName:t,context:c}=n;try{const o=p[t];if(!o)return!1;const{default:l}=await o(),r=l[t];return r?typeof r=="object"&&typeof r.isAvailable=="function"?await r.isAvailable(c):!0:!1}catch(o){throw f(t,"Failed to check if MCP tool is available: "+(o instanceof Error?o.message:String(o)),m(),o instanceof Error&&o.stack||""),o}}export{b as executeMcpTool,T as isMcpToolAvailable};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpMode } from '../types.js';
|
|
2
|
+
export declare function reportMcpToolCalled(tool: string, mode: McpMode, outputLength: number): void;
|
|
3
|
+
export declare function reportMcpToolError(tool: string, message: string, mode: McpMode, stack?: string): void;
|
|
4
|
+
//# sourceMappingURL=mcp-tool-telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{telemetry as p}from"../../../telemetry/index.js";import{McpServerType as t}from"../constants.js";const c={id:t.Docs,object:"mcpServer",uri:`urn:redocly:realm:mcp:server:${t.Docs}`,server_type:t.Docs};function m(e,r,o){p.sendMcpToolCalledMessage([{...c,tool:e,mode:r,output_length:o}])}function i(e,r,o,s=""){p.sendMcpErrorMessage([{...c,tool:e,message:r,stack:s,mode:o}])}export{m as reportMcpToolCalled,i as reportMcpToolError};
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { SearchFacet, SearchFacetCount } from '@redocly/theme/core/types';
|
|
2
|
-
import type { AfterRoutesCreatedActions, SearchEngine, AddDocumentsParams, SearchDocument } from '../../../../types';
|
|
2
|
+
import type { AfterRoutesCreatedActions, SearchEngine, AddDocumentsParams, SearchDocument, AuthDetails } from '../../../../types';
|
|
3
3
|
import type { SearchRequestParams, SearchResponse, FacetCountsRequestParams } from '../../../../../types/index.js';
|
|
4
4
|
export declare class FlexSearch implements SearchEngine {
|
|
5
5
|
#private;
|
|
6
6
|
initIndexSchema(_facets: Map<string, SearchFacet>): Promise<void>;
|
|
7
7
|
addDocuments(documents: SearchDocument[], params: AddDocumentsParams): Promise<void>;
|
|
8
8
|
getIndexesSize(): number;
|
|
9
|
-
search(params: SearchRequestParams, _facets?: Map<string, SearchFacet>): Promise<SearchResponse>;
|
|
9
|
+
search(params: SearchRequestParams, auth: AuthDetails, _facets?: Map<string, SearchFacet>): Promise<SearchResponse>;
|
|
10
10
|
exportDocuments(outDir: string): Promise<void>;
|
|
11
11
|
exportIndexes(outDir: string): Promise<void>;
|
|
12
12
|
import(sourceDir: string): Promise<void>;
|
|
13
|
-
countFacets(_params: FacetCountsRequestParams, facets: Map<string, SearchFacet>): Record<string, SearchFacetCount[]>;
|
|
13
|
+
countFacets(_params: FacetCountsRequestParams, _auth: AuthDetails, facets: Map<string, SearchFacet>): Record<string, SearchFacetCount[]>;
|
|
14
14
|
cleanupFacetValues(_actions: AfterRoutesCreatedActions): void;
|
|
15
15
|
}
|
|
16
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFile as w,readdir as y,appendFile as E}from"node:fs/promises";import m from"node:path";import{existsSync as F}from"node:fs";import{SEARCH_GROUP_FACET_FIELD as I,SEARCH_PRODUCT_FIELD as C,SEARCH_VERSION_FIELD as $}from"../../../../../constants/common.js";import{SEARCH_INDEX_FIELDS as A,SEARCH_DATA_EXPORT_FOLDER as _,SEARCH_MAX_INMEMORY_DOCUMENTS_COUNT as O}from"../../../../constants/plugins/search.js";import{telemetryTraceStep as v}from"../../../../telemetry/helpers/trace-step.js";import{envConfig as N}from"../../../../config/env-config.js";import{ensureDir as h}from"../../../../utils/index.js";import{FlexSearchIndex as j}from"./search-index.js";class J{#e=new Map;#s;#t=0;async initIndexSchema(
|
|
1
|
+
import{readFile as w,readdir as y,appendFile as E}from"node:fs/promises";import m from"node:path";import{existsSync as F}from"node:fs";import{SEARCH_GROUP_FACET_FIELD as I,SEARCH_PRODUCT_FIELD as C,SEARCH_VERSION_FIELD as $}from"../../../../../constants/common.js";import{SEARCH_INDEX_FIELDS as A,SEARCH_DATA_EXPORT_FOLDER as _,SEARCH_MAX_INMEMORY_DOCUMENTS_COUNT as O}from"../../../../constants/plugins/search.js";import{telemetryTraceStep as v}from"../../../../telemetry/helpers/trace-step.js";import{envConfig as N}from"../../../../config/env-config.js";import{ensureDir as h}from"../../../../utils/index.js";import{FlexSearchIndex as j}from"./search-index.js";class J{#e=new Map;#s;#t=0;async initIndexSchema(e){this.#s={document:{id:"id",tag:"tags",index:A},worker:!1,tokenize:"forward",context:{depth:2,resolution:9}}}#n(e,s){const n=this.#e.get(e);if(n)return n.find(o=>o.id===s)}#o(e,s){let n=this.#n(e,s);return n||(n=new j(s,this.#s),this.#e.set(e,[...this.#e.get(e)??[],n])),n}async addDocuments(e,s){if(e.length){const{group:n,locale:o,outDir:a}=s,i=this.#o(o,n);for(const c of e)i.add(c),N.isBuildMode&&(this.#t++,this.#t>=O&&await this.exportDocuments(a))}}getIndexesSize(){return this.#e.size}async search(e,s,n){return await v("search",async o=>{const{query:a,locale:i,filter:c,loadMore:r}=e,l=this.#e.get(i)??[];let f=[],d="",x=["v:default"];if(o?.setAttribute("locale",i),c)for(const t of c)t.field===I?f=[...f,...t.values]:t.field===C?d=`p:${t.values[0]}`:t.field===$&&t.values.length&&t.values.length===2&&(x=[...x,`v:${t.values[0]}:${t.values[1]}`]);const g={auth:s,query:a,offset:0,SEARCH_GROUP_FACET_FIELD:I,product:d,versions:x},p=[];let u={facets:{},documents:{}};if(r){const t=this.#n(i,r.groupKey);t&&p.push(t.search({...g,offset:r.offset}))}else for(const t of l)f&&f.length?f.includes(t.id)&&p.push(t.search(g)):p.push(t.search(g));const R=await Promise.all(p);for(const t of R){u.documents={...u.documents,...t.documents};for(const[D,S]of Object.entries(t.facets))u.facets[D]?u.facets[D]=[...u.facets[D],...S]:u.facets[D]=S}return u})}async exportDocuments(e){const s='{"documents":[',n=h(m.join(e,_));for(const[o,a]of this.#e){const i=h(m.join(n,o));for(const c of a){const r=Array.from(c.documents);if(r.length===0)continue;const l=h(m.join(i,`${c.id}.json`)),f=!F(l),d=JSON.stringify(r).substring(1).slice(0,-1),x=f?s+d:","+d;await E(l,x,{encoding:"utf8"}),c.clearDocuments()}}this.#t=0}async exportIndexes(e){const s=h(m.join(e,_));for(const[n,o]of this.#e){const a=h(m.join(s,n));for(const i of o){const c=h(m.join(a,`${i.id}.json`)),r={};await i.export((f,d)=>{r[f]=d});const l=`],"index":${JSON.stringify(r)}}`;await E(c,l,{encoding:"utf8"})}}this.#e.clear()}async import(e){const s=`${e}/${_}`;if(!F(s))return;const n=await y(s);for(const o of n){const a=await y(`${s}/${o}`);for(const i of a){const c=`${s}/${o}/${i}`,r=JSON.parse(await w(c,"utf-8")),l=m.parse(i).name;await this.#o(o,l).import(r)}}}countFacets(e,s,n){const o={};for(const[a,i]of n)o[a]=i.values.map(c=>({value:c,count:0,isCounterVisible:!1}));return o}cleanupFacetValues(e){}}export{J as FlexSearch};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SearchFacet } from '@redocly/theme/core/types';
|
|
2
|
-
import type { SearchEngineType, AfterRoutesCreatedActions, AddDocumentsParams, SearchDocument } from '../../../types';
|
|
2
|
+
import type { SearchEngineType, AfterRoutesCreatedActions, AddDocumentsParams, SearchDocument, AuthDetails } from '../../../types';
|
|
3
3
|
import type { FacetCountsRequestParams, GlobalData, SearchRequestParams, SearchResponse } from '../../../../types/index.js';
|
|
4
4
|
export declare class SearchEngine {
|
|
5
5
|
#private;
|
|
@@ -8,8 +8,8 @@ export declare class SearchEngine {
|
|
|
8
8
|
constructor(type: SearchEngineType, l10n: GlobalData['l10n']);
|
|
9
9
|
initIndexSchema(searchFacets: Map<string, SearchFacet>): Promise<void>;
|
|
10
10
|
addDocuments(documents: SearchDocument[], params: AddDocumentsParams): Promise<void>;
|
|
11
|
-
search(params: SearchRequestParams, facets?: Map<string, SearchFacet>): Promise<SearchResponse>;
|
|
12
|
-
countFacets(params: FacetCountsRequestParams, facets: Map<string, SearchFacet>): Promise<Record<string, import("@redocly/theme/core/types").SearchFacetCount[]>>;
|
|
11
|
+
search(params: SearchRequestParams, auth: AuthDetails, facets?: Map<string, SearchFacet>): Promise<SearchResponse>;
|
|
12
|
+
countFacets(params: FacetCountsRequestParams, auth: AuthDetails, facets: Map<string, SearchFacet>): Promise<Record<string, import("@redocly/theme/core/types").SearchFacetCount[]>>;
|
|
13
13
|
export(outDir: string): Promise<void>;
|
|
14
14
|
import(sourceDir: string): Promise<void>;
|
|
15
15
|
cleanupFacetValues(actions: AfterRoutesCreatedActions): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DEFAULT_LOCALE_PLACEHOLDER as
|
|
1
|
+
import{DEFAULT_LOCALE_PLACEHOLDER as n}from"../../../../constants/common.js";import{FlexSearch as a}from"./flexsearch/index.js";import{Typesense as c}from"./typesense/index.js";class h{type;l10n;#s={flexsearch:a,typesense:c};#e;constructor(e,t){this.type=e,this.l10n=t,this.#e=new this.#s[e]}async initIndexSchema(e){await this.#e.initIndexSchema?.(e)}async addDocuments(e,t){return this.#e.addDocuments(e,t)}async search(e,t,s){return this.#e.search({...e,locale:this.#t(e)},t,s)}async countFacets(e,t,s){return this.#e.countFacets({...e,locale:this.#t(e)},t,s)}async export(e){await this.#e.exportDocuments(e),await this.#e.exportIndexes(e)}async import(e){return this.#e.import(e)}#t(e){const t=e.locale||this.l10n?.defaultLocale||n;return t===this.l10n?.defaultLocale?n:t.toLowerCase()}cleanupFacetValues(e){return this.#e.cleanupFacetValues(e)}}export{h as SearchEngine};
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import type { SearchFacet, SearchFacetCount } from '@redocly/theme/core/types';
|
|
2
2
|
import type { SearchRequestParams, SearchResponse as ISearchResponse, FacetCountsRequestParams } from '../../../../../types/index.js';
|
|
3
|
-
import type { AfterRoutesCreatedActions, SearchEngine, AddDocumentsParams, SearchDocument } from '../../../../types';
|
|
3
|
+
import type { AfterRoutesCreatedActions, SearchEngine, AuthDetails, AddDocumentsParams, SearchDocument } from '../../../../types';
|
|
4
4
|
export declare class Typesense implements SearchEngine {
|
|
5
5
|
#private;
|
|
6
6
|
constructor();
|
|
7
7
|
initIndexSchema(searchFacets: Map<string, SearchFacet>): Promise<void>;
|
|
8
8
|
addDocuments(documents: SearchDocument[], params: AddDocumentsParams): Promise<void>;
|
|
9
|
-
search(params: SearchRequestParams): Promise<ISearchResponse>;
|
|
9
|
+
search(params: SearchRequestParams, auth: AuthDetails): Promise<ISearchResponse>;
|
|
10
10
|
exportDocuments(outDir: string): Promise<void>;
|
|
11
11
|
exportIndexes(outDir: string): Promise<void>;
|
|
12
12
|
import(_sourceDir: string): Promise<void>;
|
|
13
|
-
countFacets(params: FacetCountsRequestParams,
|
|
13
|
+
countFacets(params: FacetCountsRequestParams, auth: AuthDetails): Promise<Record<string, SearchFacetCount[]>>;
|
|
14
14
|
cleanupFacetValues(actions: AfterRoutesCreatedActions): void;
|
|
15
15
|
}
|
|
16
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{appendFile as
|
|
1
|
+
import{appendFile as g}from"node:fs/promises";import{existsSync as I}from"node:fs";import m from"node:path";import{Client as $}from"typesense";import{SEARCH_GROUP_FACET_FIELD as E,SEARCH_PRODUCT_FIELD as R,SEARCH_RBAC_FIELD as A,SEARCH_VERSION_FIELD as f}from"../../../../../constants/common.js";import{BASE_SEARCH_DOCUMENT as T,DISABLE_DEEP_LINK_IF_FIELDS_EXIST as O,HIGHLIGHTED_TEXT_MAX_LENGTH as b,SEARCH_DATA_EXPORT_FOLDER as F,SEARCH_DOCUMENT_METADATA_KEY as P,SEARCH_GROUP_LIMIT as N,SEARCH_MAX_FACET_VALUES as S,SEARCH_MAX_INMEMORY_DOCUMENTS_COUNT as C}from"../../../../constants/plugins/search.js";import{telemetryTraceStep as D}from"../../../../telemetry/helpers/trace-step.js";import{envConfig as p}from"../../../../config/env-config.js";import{ensureDir as d}from"../../../../utils/index.js";class U{#e=null;#o="";#t=[{name:"title",type:"string",facet:!1,optional:!0},{name:"text",type:"string",facet:!1,optional:!0},{name:"path",type:"string[]",facet:!1,optional:!0},{name:"isAdditionalOperation",type:"bool",facet:!1,optional:!0,queryable:!1},{name:"parameters",type:"object[]",facet:!1,optional:!0},{name:R,type:"string",facet:!0,optional:!0},{name:f,type:"object",facet:!0,optional:!0},{name:A,type:"string[]",facet:!0},{name:"metadata_curated",type:"bool",facet:!1,optional:!0,queryable:!1},{name:"metadata_keywords_excludes",type:"string[]",facet:!1,optional:!0,queryable:!1},{name:"metadata_keywords_includes",type:"string[]",facet:!1,optional:!0,queryable:!1}];#s=new Map;#n={ORGANIZATION_ID:p.ORGANIZATION_ID??"",PROJECT_ID:p.PROJECT_ID??"",TYPESENSE_API_URL:p.TYPESENSE_API_URL??"",TYPESENSE_API_KEY:p.TYPESENSE_API_KEY??""};constructor(){if(!p.isBuildMode){for(const[e,t]of Object.entries(this.#n))if(!t)throw new Error(`Cannot initialize search index. ${e} is not set`);this.#o=`${this.#n.ORGANIZATION_ID}_${this.#n.PROJECT_ID}_`,this.#e=new $({nodes:[{url:this.#n.TYPESENSE_API_URL}],apiKey:this.#n.TYPESENSE_API_KEY,connectionTimeoutSeconds:5})}}async initIndexSchema(e){this.#p(e)}async addDocuments(e,t){e.push(T);const{locale:n,outDir:r}=t,s=e.map(a=>{const o={...a},c=a[P];return c&&(c.curated&&(o.metadata_curated=c.curated),c.excludes&&(o.metadata_keywords_excludes=c.excludes),c.includes&&(o.metadata_keywords_includes=c.includes)),o}),i=this.#s.get(n)??[];this.#s.set(n,i.concat(s)),i.length+e.length>=C&&await this.exportDocuments(r)}async search(e,t){return await D("search",async n=>{const{query:r,locale:s,filter:i,loadMore:a}=e,o=this.#c(s),c={collection:o,q:r||"*",query_by:this.#l(),max_facet_values:S};if(n?.setAttribute("collectionName",o),n?.setAttribute("locale",s),this.#e)if(a){const{groupKey:l,offset:u}=a,h={offset:u,filter_by:this.#r(t,i),facet_by:"*"};return n?.setAttribute("isLoadMore",!0),n?.setAttribute("filter",h.filter_by),this.#u(await this.#e.collections(o).documents().search({...c,...h}),l)}else{const l={group_by:this.#m(),group_limit:N,filter_by:this.#r(t,i)};n?.setAttribute("groups",l.group_by),n?.setAttribute("filter",l.filter_by);const u=[l,...this.#y(t,i)];return this.#f(await this.#e?.multiSearch.perform({searches:u},c),i)}else return{facets:{},documents:{}}})}#u(e,t){const n={facets:{},documents:{[t]:[]}};if(e.hits&&e.hits.length)for(const r of e.hits)n.documents[t].push({document:this.#i(r),highlight:this.#a(r)});return n}#f(e,t){const n={facets:{},documents:{}};for(const r of this.#_(t))n.documents[r]=[];if("results"in e)for(const r of e.results){if(r.facet_counts&&r.facet_counts.length)for(const s of r.facet_counts)n.facets[s.field_name]=s.counts.map(i=>({value:i.value,count:i.count}));if(r.grouped_hits&&r.grouped_hits.length)for(const s of r.grouped_hits){const i=s.group_key[0],a=[];for(const o of s.hits)a.push({document:this.#i(o),highlight:this.#a(o)});n.documents[i]=a}}return n}#i(e){return this.#h(e)}#a(e){const t={},n=[];for(const[r,s]of Object.entries(e.highlight??{}))if(Array.isArray(s)){if(r==="path"){const i=s,a=[];for(const o of i)a.push(o.snippet);t.path=a}else if(r==="parameters"){const i=s;for(const a of i){let o=!1;for(const[c,l]of Object.entries(a))if(c!=="deepLink")if(Array.isArray(l))for(const u of l)u.matched_tokens?.length&&(o=!0);else l.matched_tokens?.length&&(o=!0);if(o){const c={name:a.name?.snippet||"",description:a.description?.snippet||"",place:a.place?.snippet||"",path:a.path?.map(l=>l?.snippet)||[]};t.parameters=[c];break}}}}else t[r]=s.snippet,n.push(r);for(const[r,s]of Object.entries(e.document))!n.includes(r)&&typeof s=="string"&&(t[r]=s.length>b?`${s.substring(0,b)}...`:s);return t.parameters||(t.parameters=[]),t}#h(e){let t;const n=Object.keys(e.highlight);for(const s of O)if(n.some(i=>i===s))return e.document;const r=e.highlight.parameters;if(r){for(const s of r)for(const[i,a]of Object.entries(s))if(i!=="deepLink"){if(Array.isArray(a)){for(const o of a)if(o.matched_tokens?.length){t=s.deepLink.snippet;break}}else if(a.matched_tokens?.length){t=s.deepLink.snippet;break}}}if(t){const s=t.split("#")[1];return{...e.document,url:`${e.document.url}#${s}`}}return e.document}async exportDocuments(e){const t='{"documents":[',n=d(m.join(e,F));for(const[r,s]of this.#s){if(s.length===0)continue;const i=d(m.join(n,`${r}.json`)),a=!I(i),o=JSON.stringify(s).substring(1).slice(0,-1),c=a?t+o:","+o;await g(i,c,{encoding:"utf8"}),this.#s.set(r,[])}}async exportIndexes(e){const t=d(m.join(e,F));for(const n of this.#s.keys()){const r=d(m.join(t,`${n}.json`)),s=`],"schemaFields":${JSON.stringify(this.#t)}}`;await g(r,s,{encoding:"utf8"})}}async import(e){}async countFacets(e,t){return await D("search.facets",async n=>{const{locale:r,query:s,facetQuery:i,filter:a,field:o}=e,c=this.#c(r),l={q:s||"*",query_by:this.#l(),facet_by:"*",facet_query:this.#d(i,o),filter_by:this.#r(t,a,o),max_facet_values:S};if(n?.setAttribute("collectionName",c),n?.setAttribute("query",l.q),n?.setAttribute("facetQuery",l.facet_query),n?.setAttribute("filter",l.filter_by),this.#e){const u={},h=await this.#e.collections(c).documents().search(l);if(h.facet_counts&&h.facet_counts.length)for(const _ of h.facet_counts)u[_.field_name]=_.counts.map(y=>({value:y.value,count:y.count,isCounterVisible:!!s||(a?.length||0)>0}));return u}else return{}})}#c(e){return`${this.#o}${e}`}#p(e){for(const[t,{queryable:n}]of e)this.#t.find(r=>r.name===t)||this.#t.push({queryable:n,name:t,type:"string",facet:!0,optional:!0})}#l(){return this.#t.filter(e=>e.facet?e.queryable:e.queryable!==!1).map(e=>e.name).join(",")}#m(){return this.#t.filter(e=>e.facet&&e.name===E).map(e=>e.name).join(",")}#r(e,t,n){const r=`${A}:[${e.teams.map(i=>`'${i}'`).join(", ")}]`;let s=`${f}.isDefault:true`;if(t&&t.length){const i=t.filter(o=>o.field!==n&&o.field!==f).map(o=>{const c=o.values.map(l=>`'${l}'`);return c.length?`${o.field}:[${c.join(", ")}]`:""}).join(" && "),a=t.find(o=>o.field===f);if(a&&a.values.length&&a.values.length===2){const o=a.values[0],c=a.values[1],l=`(${f}.folderId:! ${o} && ${f}.isDefault:true)`,u=`(${f}.folderId:${o} && ${f}.version:${c})`;s=`(${l} || ${u})`}return i?`${r} && ${i} && ${s}`:`${r} && ${s}`}else return`${r} && ${s}`}#d(e,t){return e&&t?`${t}:${e}`:""}#_(e){const t=[];if(e&&e.length)for(const n of e)n.field===E&&t.push(...n.values);return t}#y(e,t){const n=[],r=this.#t.filter(s=>s.facet);for(const s of r){const i={facet_by:s.name,filter_by:this.#r(e,t,s.name)};n.push(i)}return n}cleanupFacetValues(e){const t=e.getSearchFacets();t.forEach(n=>{n.values=[]}),e.setSearchFacets(t)}}export{U as Typesense};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{SitemapStream as l,streamToPromise as d}from"sitemap";import{Readable as p}from"stream";import{writeFileSync as y}from"fs";import g from"path";import{SITEMAP_FILE_NAME as h}from"../../constants/common.js";import{ServerRoutes as w}from"../../../constants/
|
|
1
|
+
import{SitemapStream as l,streamToPromise as d}from"sitemap";import{Readable as p}from"stream";import{writeFileSync as y}from"fs";import g from"path";import{SITEMAP_FILE_NAME as h}from"../../constants/common.js";import{ServerRoutes as w}from"../../../constants/api.js";import{withPathPrefix as P}from"@redocly/theme/core/utils";import{logger as s}from"../../tools/notifiers/logger.js";import{isResourcePubliclyAccessible as b}from"../../utils/index.js";import{telemetryTraceStep as S}from"../../../cli/telemetry/helpers/trace-step.js";async function R(t,n){if(!t)return;const r=t.endsWith(".tsx"),i=t.endsWith(".md");if(!(!r&&!i))try{const o=r?"react-frontmatter":"markdown-frontmatter",e=await n.load(t,o);return e.data.frontmatter?.seo?.priority??e.data.seo?.priority}catch{return}}async function v(t,n){const r=t.fsPath?await R(t.fsPath,n):void 0;if(typeof r=="number"){if(r>=0&&r<=1)return r;s.warn(`Invalid SEO priority value "${r}" found for route "${t.slug}". Priority must be between 0 and 1. Using default priority instead.`)}const i=t.versions?.find(o=>o.active);return i?.default||!i?.5:.3}async function $(){return{id:"sitemap",async afterRoutesCreated(t,n){await S("build.plugin.sitemap",async r=>{const{seo:i}=t.getConfig();if(r?.setAttribute("config",JSON.stringify(i||{})),!i?.siteUrl)return;const o=t.getAllRoutes().filter(e=>!e.excludeFromSearch&&b(e,t.getConfig())&&!Object.keys(w).includes(e.slug));if(o.length)try{const e=g.join(t.outdir,h),m=new l({hostname:i.siteUrl}),c=await Promise.all(o.map(async a=>{const u=await v(a,n.cache);return{url:P(a.slug),priority:u}})),f=await d(p.from(c).pipe(m)).then(a=>a.toString());y(e,f),t.hasSitemap=!0}catch(e){r?.error(e),s.error(`Error creating sitemap: ${e.message}`)}})}}}export{$ as sitemapPlugin};
|
|
@@ -17,6 +17,7 @@ import type { Logger } from '../../tools/notifiers/logger.js';
|
|
|
17
17
|
import type { AiDocumentsStore } from '../../plugins/search/types';
|
|
18
18
|
import type { ParseMarkdocOpts } from '../../types/plugins/markdown';
|
|
19
19
|
import type { MarkdocConfigProps } from '../../plugins/markdown/compiler';
|
|
20
|
+
import type { ToolAnnotations } from '@redocly/mcp-typescript-sdk/types.js';
|
|
20
21
|
export type ResolveItemsOptions = {
|
|
21
22
|
groupCustomSidebars?: boolean;
|
|
22
23
|
locale?: string;
|
|
@@ -124,6 +125,8 @@ export type McpToolSchema = {
|
|
|
124
125
|
name: string;
|
|
125
126
|
description: string;
|
|
126
127
|
schema: Record<string, unknown>;
|
|
128
|
+
outputSchema?: Record<string, unknown>;
|
|
129
|
+
annotations?: ToolAnnotations;
|
|
127
130
|
};
|
|
128
131
|
export type McpToolRegistration = McpToolSchema & {
|
|
129
132
|
importPath: string;
|
|
@@ -9,11 +9,11 @@ import type { SEARCH_DOCUMENT_METADATA_KEY } from '../../constants/plugins/searc
|
|
|
9
9
|
export type SearchEngineType = 'flexsearch' | 'typesense';
|
|
10
10
|
export type SearchEngine = {
|
|
11
11
|
addDocuments(documents: SearchDocument[], params: AddDocumentsParams): Promise<void>;
|
|
12
|
-
search(params: SearchRequestParams):
|
|
12
|
+
search(params: SearchRequestParams, auth: AuthDetails): Promise<SearchResponse>;
|
|
13
13
|
exportDocuments(outDir: string, facets: Map<string, SearchFacet>): Promise<void>;
|
|
14
14
|
exportIndexes(outDir: string, facets: Map<string, SearchFacet>): Promise<void>;
|
|
15
15
|
import(sourceDir: string): Promise<void>;
|
|
16
|
-
countFacets(params: FacetCountsRequestParams, facets: Map<string, SearchFacet>): Record<string, SearchFacetCount[]> | object;
|
|
16
|
+
countFacets(params: FacetCountsRequestParams, auth: AuthDetails, facets: Map<string, SearchFacet>): Record<string, SearchFacetCount[]> | object;
|
|
17
17
|
};
|
|
18
18
|
export type SearchDocumentMetadata = Partial<{
|
|
19
19
|
includes: string[];
|
|
@@ -36,6 +36,14 @@ export type UserIDToken = {
|
|
|
36
36
|
sub: string;
|
|
37
37
|
[k: string]: unknown;
|
|
38
38
|
};
|
|
39
|
+
export type ValidatedJsonInput<T> = {
|
|
40
|
+
in: {
|
|
41
|
+
json: T;
|
|
42
|
+
};
|
|
43
|
+
out: {
|
|
44
|
+
json: T;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
39
47
|
declare global {
|
|
40
48
|
interface Request {
|
|
41
49
|
context: RequestContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import y from"path";import T from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as L,REDOCLY_ROUTE_RBAC as R}from"@redocly/config";import{
|
|
1
|
+
import y from"path";import T from"picomatch";import"../node-crypto-polyfill.js";import{REDOCLY_TEAMS_RBAC as L,REDOCLY_ROUTE_RBAC as R}from"@redocly/config";import{ServerRoutes as w}from"../../constants/api.js";import{DEFAULT_ANONYMOUS_VISITOR_TEAM as x,PUBLIC_RBAC_SCOPE_ITEM as A,RBAC_ALL_OTHER_TEAMS as u,DEFAULT_RBAC_SCOPE as _}from"../../constants/common.js";import{DEPRECATED_PUBLIC_API_DEFINITIONS_FOLDER as I,PUBLIC_API_DEFINITIONS_FOLDER as j,PUBLIC_ASSETS_FOLDER as N}from"../constants/common.js";import{removeTrailingSlash as k}from"../../utils/url/remove-trailing-slash.js";import{removeLeadingSlash as B}from"../../utils/url/remove-leading-slash.js";import{parsePathVersions as b}from"../../utils/path/parse-path-versions.js";import{reporter as M}from"../tools/notifiers/reporter.js";import{bold as W}from"../tools/notifiers/helpers/colors.js";import{shaDirPathShort as U}from"../utils/crypto/sha-dir-path-short.js";import{isTruthy as $}from"../../utils/guards/is-truthy.js";import{canExpandConfig as v,expandRbacConfig as Y,getTeamFolderDefaults as z,parseTeamFoldersTemplate as K,parseTeamNameTemplate as H}from"./rbac-expand.js";import{getUserParamsFromCookies as G}from"../web-server/auth.js";import{getDeeperGlobPattern as V}from"./globs.js";import{EntitlementsProvider as J}from"../entitlements/entitlements-provider.js";const C=["NONE","READ","TRIAGE","WRITE","MAINTAIN","ADMIN"],Q=new Set(["x-parsed-md-description","x-parsed-md-summary"]);function xt(t,e){const r=C.indexOf(t.toUpperCase()),n=C.indexOf(e.toUpperCase());return r>n?t:e}const E={};function O(t,e){if(!t?.content)return A;const r=t.content,{slug:n,fsPath:o}=e;if(!n&&!o)return A;const s=f=>{const d=`slug:${f}`,p=E[d]??T(f);E[d]=p;const D=`fsPath:${f}`,S=E[D]??T(B(f));return E[D]=S,!!(n&&p(n))||!!(o&&S(o))};if(et(n||o||"")&&Object.keys(r).filter(p=>s(p)).length===0)return r[_]||A;const a=Object.keys(r).filter(f=>s(f));if(a.length==0)return A;const l=a.map(f=>T.scan(f,{tokens:!0,parts:!0}));let h=l[0];for(let f=1;f<l.length;f++)h=V(h,l[f]);return r[h.input]}function gt(t,e,r={},n=!1){if(n&&Object.keys(r).length===0)return e.isAuthenticated;const o=r.features?.[t];return o?e.teams.some(s=>o[s]&&o[s].toLowerCase()!=="none"):!0}function Dt(t,e){return P(t,{isAuthenticated:!1,teams:[x]},e.access?.rbac||{},e.access?.requiresLogin||!1)}function P(t,e={},r={},n=!1){if(t.slug&&typeof t.slug=="string"&&Object.values(w).some(a=>{const l=a.split(":")[0].replace(/\/$/,"");return t.slug===l||t.slug?.startsWith(a)})||typeof t.slug=="string"&&t.slug?.endsWith("/mcp")&&J.instance().canAccessFeature("mcp"))return!0;if(n&&Object.keys(r).length===0)return!!e.isAuthenticated;const o=Y(r,e.teams||[]),s=t[L]||O(o,t[R]||{});if(Object.keys(s||{}).length===0)return!1;if(Object.keys(s).length===1&&s[u]&&s[u].toLowerCase()!=="none")return!0;const i=(e?.email?[...e?.teams||[],e?.email]:e?.teams)||[],c=[];for(const a of i??[])s[a]?c.push(s[a]):s[u]&&a!==e?.email&&c.push(s[u]);return c.length?c.some(a=>a.toLowerCase()!=="none"):!1}function St(t,e,r,n){if(!t.startsWith(j)&&!t.startsWith(I))return!0;const o=t.replace(new RegExp(`^${j}/`),"").replace(new RegExp(`^${I}/`),""),i=o==="."?"":o,c={[R]:{slug:t,fsPath:i},slug:t};return P(c,n,e,r)}function Lt(t,e,r,n,o){if(!t.startsWith(N))return!0;const s=t.match(/.*\..{64}\.([A-Fa-f0-9]{8})\.[^\.]+$/)?.[1];if(!s)return!0;const i=n[s];if(!i)return!0;const{base:c,ext:a}=y.parse(t),l=c.split(".")[0],h=a.split(".").join(""),d=i==="."?"":i,p={[R]:{slug:t,fsPath:y.posix.join(d,`${l}.${h}`)},slug:t};return P(p,o,e,r)}async function _t(t,e){const{isAuthenticated:r=!1,idpAccessToken:n,federatedAccessToken:o,federatedIdToken:s,...i}=await G(t,e),{teams:c=[]}=i;let a;return r?a=c.filter(l=>l!==x):a=[x],{isAuthenticated:r,idpAccessToken:n,teams:a,claims:i}}function F(t,e,r={},n=!1){if(!t)return t;if(Array.isArray(t)){const o=[];for(const s of t){const i=F(s,e,r,n);i!==void 0&&o.push(i)}return tt(o)}if(typeof t=="object"){if(!P(t,e,r,n))return;let o=!1;const s={};for(const i in t){if(i===L||i===R)continue;if(Q.has(i)){s[i]=t[i];continue}const c=F(t[i],e,r,n);if(i==="items"&&Array.isArray(c)&&c.length===0&&t[i].length!==0){o=!0;continue}c!==void 0&&(s[i]=c),i==="paths"&&X(c)&&Z(c)}return o?void 0:s}return t}function It(t){return typeof t=="string"?t.split(" ").filter(Boolean):Array.isArray(t)?t.map(e=>e.toString()):[]}function jt(t,e){if(!e)return;const r=e.content;if(!r)return e;const n=Object.entries(r).flatMap(([s,i])=>s===_?[[s,i]]:[[s,i],...t.localeFolders.map(c=>[s.startsWith("/")?`/${c.toLocaleLowerCase()}${s}`:y.posix.join(t.localizationFolder,c,s),i])]),o=Object.fromEntries(n);return{...e,content:o}}async function Ct(t,e){if(!e)return{};const r={},n=new Set((await t.scan()).flatMap(({relativePath:o})=>{const{versionFolderPath:s}=b(o)||{},i=y.dirname(o);return s?[s,i]:i}));for(const o of n)r[U(o)]=o;return r}const m=t=>typeof t=="object"&&t!==null&&!Array.isArray(t);function X(t){return m(t)&&Object.keys(t).length>0}function Z(t){for(const e of Object.keys(t)){const r=t[e];m(r)&&Object.keys(r).length===0&&delete t[e]}}function q(t){return m(t)&&t.type==="separator"}function tt(t){const e=[];let r;for(const n of t){if(q(n)){r=n;continue}r&&(e.push(r),r=void 0),e.push(n)}return e}function et(t){return t?t.split("/").filter(Boolean).some(r=>r.startsWith(".")):!1}const rt=t=>{if(t&&m(t)&&("content"in t&&m(t.content)||"reunite"in t&&m(t.reunite)||"features"in t&&m(t.features)||t.teamFolders&&t.teamNamePatterns)){const e=Object.values(t.content||{});if(e.length===0)return!0;if(e.every(m))return e.every(r=>Object.values(r).every(n=>typeof n=="string"))}return!1},Ft=async t=>{if(t){if(Object.keys(t).length===0)return{};if(rt(t))return nt(t);await M.panicOnContentError(`You are using an incorrect format of ${W("rbac:")} configuration. See: https://redocly.com/docs/realm/access`)}},nt=t=>{const e={...t};if(e.content){const r={};for(const n in e.content)if(e.content[n]!==void 0){const o=k(n);r[o]=e.content[n]}e.content=r}return e};function wt(t,e){const r=t.fsPath,n=t.slug,o=[];if(v(e)&&(r||n)){const s=[r,n].filter($),i=K(e,s);if(i){const c=e?.teamNamePatterns?.map(l=>l.replace("{teamPathSegment}",i.teamPathSegment).replace("{projectRole}","read"))??[];o.push(...c);const a=O({content:{...z(e),...e.content}},t);o.push(...g(a))}else{const c=O(e,t);o.push(...g(c))}}else{const s=O(e,t);o.push(...g(s))}return ot(e,o)}function g(t){if(!t)return[];const e=[],r=u in t?{authenticated:t[u],anonymous:t[u]}:{};for(const[n,o]of Object.entries({...r,...t}))o.toLowerCase()!=="none"&&n!==u&&e.push(n);return e}function ot(t,e){return e.map(n=>H(t,n)??{teamName:n}).map(n=>n.projectRole&&n.projectRole!=="READ"?n.teamName?.toLowerCase().replace(n.projectRole?.toLowerCase?.()??"","read")??"":n.teamName?.toLowerCase()??"")}export{C as PROJECT_ROLES_ORDERED_BY_ACCESS_LEVEL,jt as applyL10nToRbacConfig,Lt as canAccessAsset,gt as canAccessFeature,P as canAccessResource,St as canDownloadApiDefinition,ot as expandTeamsForRead,g as extractTeamsFromScopeItems,F as filterDataByAccessDeep,_t as getAuthDetailsFromCookies,xt as getHigherRole,wt as getRbacTeamsListForResource,O as getScopeItemsForResource,rt as isRbacConfigValid,Dt as isResourcePubliclyAccessible,nt as normalizeRbacConfig,Ft as parseRbacConfig,It as parseTeamClaimToArray,Ct as resolveDirectoryHashes};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import"../node-crypto-polyfill.js";import{DOMParser as P}from"@xmldom/xmldom";import{SignedXml as J}from"xml-crypto";import q from"xpath";import{deflateSync as K,inflateSync as Y}from"fflate";import{createHash as Q}from"crypto";import{ulid as X}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as Z}from"@redocly/config";import{AUTH_URL as G,JWT_SECRET_KEY as C}from"../constants/common.js";import{envConfig as ee}from"../config/env-config.js";import{getPathPrefix as te,withPathPrefix as ne}from"@redocly/theme/core/utils";import{AuthCookieNames as A,DEFAULT_AUTHENTICATED_TEAM as re,REQUIRED_OIDC_SCOPES as
|
|
1
|
+
import"../node-crypto-polyfill.js";import{DOMParser as P}from"@xmldom/xmldom";import{SignedXml as J}from"xml-crypto";import q from"xpath";import{deflateSync as K,inflateSync as Y}from"fflate";import{createHash as Q}from"crypto";import{ulid as X}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as Z}from"@redocly/config";import{AUTH_URL as G,JWT_SECRET_KEY as C}from"../constants/common.js";import{envConfig as ee}from"../config/env-config.js";import{getPathPrefix as te,withPathPrefix as ne}from"@redocly/theme/core/utils";import{ServerRoutes as N}from"../../constants/api.js";import{AuthCookieNames as A,DEFAULT_AUTHENTICATED_TEAM as re,REQUIRED_OIDC_SCOPES as R}from"../../constants/common.js";import{appendQueryParams as oe}from"../../utils/url/append-query-params.js";import{parseHttpsUrl as b}from"../../utils/url/parse-https-url.js";import{logger as ae}from"../tools/notifiers/logger.js";import{randomString as se}from"../utils/crypto/random-string.js";import{randomUUID as v}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as w,JwtTokenExpired as ie}from"./jwt/types.js";import*as f from"./jwt/jwt.js";import{parseTeamClaimToArray as ce}from"../utils/index.js";import{arrayBufferToBase64 as ue,decodeBase64 as U,encodeBase64URL as le,urlSafeBase64 as j}from"./jwt/encode.js";import{formatSamlCertificate as de}from"./utils/format-saml-certificate.js";function V(e){return e?.type===u.OIDC}function me(e){return e?.type===u.SAML2}async function Ze(e,t){if(V(t))return pe(e,t);if(me(t))return fe(e,t)}async function pe(e,t){const n=await F(e,t),r=new Set((t.scopes||[]).concat(R)),o=t.authorizationRequestCustomParams||{};return{type:u.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:n.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(r).join(" "),extraParams:o,pkce:t.pkce}}function fe(e,t){return{type:u.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}async function Ge(e,t,n,r,o={}){const a=new Set((r.scopes||[]).concat(R));return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:r.clientId,scope:Array.from(a).join(" "),code:t,redirect_uri:$(n),grant_type:"authorization_code",...r.clientSecret?{client_secret:r.clientSecret}:{},...o}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(s=>s.json())}function he(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:a,idpId:s,pkce:l},m,g,p){if(!t||!n||!r||!o)return{loginUrl:void 0};const i=new URL(t),h=p?.redirectUriOverride??`${e}${ne(N.OIDC_CALLBACK)}`,_={state:v(),idpId:s,redirectUri:h,redirectTo:m,branch:p?.branchOverride??ye(e),inviteCode:g,source:p?.sourceOverride??"portal",uiLocales:p?.uiLocales},y={};if(l){const d=j(se(50)),x=j(Q("sha256").update(d).digest("base64")),I="S256";i.searchParams.append("code_challenge",x),i.searchParams.append("code_challenge_method",I),y.code_verifier={value:d,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:te()||"/"}}}i.searchParams.append("client_id",n),i.searchParams.append("scope",o),i.searchParams.append("response_type",r),i.searchParams.append("redirect_uri",$(h)),i.searchParams.append("state",le(JSON.stringify(_))),p?.uiLocales&&i.searchParams.append("ui_locales",p.uiLocales);for(const d in a)a[d]!==void 0&&i.searchParams.append(d,a[d]);return{loginUrl:i.toString(),cookies:y}}function et(e,t,n,r){const o=new URL(e);return o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n),o.toString()}async function tt(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return f.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,...e.idpAccessToken?{idp_access_token:e.idpAccessToken}:{},...e.codeChallenge?{code_challenge:e.codeChallenge}:{},...e.codeChallengeMethod?{code_challenge_method:e.codeChallengeMethod}:{},iat:t,exp:n},C,w.HS256)}async function nt(e){await f.verify(e,C,w.HS256);const{payload:t}=f.decode(e);if(t.type!=="mcp_auth_code")throw new Error("Invalid authorization code type");if(!t.client_id||!t.redirect_uri)throw new Error("Authorization code missing required claims");if(typeof t.exp=="number"&&Date.now()>=t.exp*1e3)throw new Error("Authorization code expired");return t}function rt(e){const t=e||X(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcpSession",uri:`urn:redocly:realm:mcp:session:${n}`}}function $(e){const t=b(e);if(!t)return e;const n=we(t.hostname);if(n)return t.hostname=`previewauth--${n.previewBranch}${n.after}`,H(e,t);const r=B(t.hostname);return r?(t.hostname=`${r.projectSlug}.previewauth.${r.after}`,H(e,t)):e}function ye(e){const t=b(e);if(t)return B(t.hostname)?.previewBranch}function H(e,t){return e.replace(/^https:\/\/[^/?#]+/i,`https://${t.host}`)}function B(e){const t=e.split(".preview.",2);if(t.length<2)return null;const[n,r]=t,o=n.indexOf("--");if(o===-1)return null;const a=n.slice(0,o),s=n.slice(o+2);return!a||!s||s.includes(".")?null:{projectSlug:a,previewBranch:s,after:r}}function we(e){const t=e.indexOf("."),n=t===-1?e:e.slice(0,t);if(!n.startsWith("preview-"))return null;const r=n.indexOf("--");if(r===-1)return null;const o=n.slice(r+2);if(!o)return null;const a=t===-1?"":e.slice(t);return{previewBranch:o,after:a}}function Se(e){return e.type===u.OIDC}function Ae(e){return e.type===u.SAML2}function ot(e,t,n,r,o){return Se(e)?he(t,e,n,r,{uiLocales:o}):Ae(e)?ge(t,e,n,r,o):{}}function ge(e,t,n,r,o){const s=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
|
|
2
2
|
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
|
|
3
3
|
Version="2.0"
|
|
4
4
|
ID="_${v()}"
|
|
5
5
|
IssueInstant="${new Date().toISOString()}"
|
|
6
|
-
AssertionConsumerServiceURL="${e}${
|
|
6
|
+
AssertionConsumerServiceURL="${e}${N.SAML_CALLBACK}"
|
|
7
7
|
AttributeConsumingServiceIndex="0">
|
|
8
8
|
<saml:Issuer>${t.entityId}</saml:Issuer>
|
|
9
9
|
<samlp:NameIDPolicy
|
|
10
10
|
AllowCreate="true"
|
|
11
11
|
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
|
|
12
|
-
</samlp:AuthnRequest>`,l=_e(s);return{loginUrl:oe(t.ssoUrl,{SAMLRequest:l,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function _e(e){return ue(K(new TextEncoder().encode(e)).buffer)}function
|
|
12
|
+
</samlp:AuthnRequest>`,l=_e(s);return{loginUrl:oe(t.ssoUrl,{SAMLRequest:l,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal",uiLocales:o})})}}function _e(e){return ue(K(new TextEncoder().encode(e)).buffer)}function at(e){const t=U(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=Y(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function st(e){try{return JSON.parse(U(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function it(e){const t=new P().parseFromString(e,"application/xml"),r=c(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,a=c(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],l=s&&s.nodeValue||void 0,m=c(t,"//*[local-name(.)='Audience']/text()")[0],g=m&&m.nodeValue||void 0,i=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",h=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],_=h&&h.nodeValue||"",y=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],d=y&&y.nodeValue||"",x=c(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],I=xe(x),O={},D=c(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(D.length)for(const M of D){const k=c(M,"./@Name")[0];if(k.nodeValue){const E=c(M,"./*[local-name(.)='AttributeValue']/text()")[0];E?.nodeValue&&(O[k.nodeValue]=E.nodeValue)}}return{uid:_,success:r,expiresAt:I,issuerId:l,entityId:g,attrs:O,cert:i,nameFormat:d,destination:a}}function xe(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),n=L(Date.now()),r=L(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function L(e){return Math.floor(e/1e3)}const T={},S={jwks:{}};async function F(e,t){if(!T[e]){const n=t.configurationUrl?await z(t.configurationUrl):t.configuration;T[e]=Ie()?Ce(n):n}return T[e]}function Ie(){const e=ee.REDOCLY_ENFORCE_RESIDENCY;return!!e&&e.includes("host.docker.internal")}function Ce(e){if(typeof e!="object"||e===null)return e;const t={...e};for(const n of Object.keys(t)){const r=t[n];typeof r=="string"&&r.includes("://localhost")&&(t[n]=r.replace("://localhost","://host.docker.internal"))}return t}async function Le(e){for(const t of Object.keys(e)){const n=e[t];if(!V(n))continue;const r=await F(t,n);if(r.jwks_uri){const o=await z(r.jwks_uri);for(const a of o.keys)S.jwks[a.kid]={...a,idpId:t}}}}async function z(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function ct(e){return fetch(`${G}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function ut(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com","cba.au.redocly.com"].some(r=>Te(t.hostname,r))}function Te(e,t){return e===t||e.endsWith(`.${t}`)}async function lt(e,t){const n=new P().parseFromString(e,"application/xml"),r=c(n,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!r)throw new Error("Cannot find Signature in the SAML response");const o=de(t),a=new J({publicCert:o});a.loadSignature(r);try{return a.checkSignature(e)}catch{return!1}}function dt(e,t,n,r){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=n["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let o;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(o=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/.+@.+/)&&(o=e);const a=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=a?.match(/.+@.+/);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?a:void 0),o=o?.toLowerCase(),{sub:e,given_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:n["http://schemas.microsoft.com/identity/claims/displayname"]||a,email:o,email_verified:!0,teams:r?ce(n[r]):[]}}function W(e,t={}){return e.map(n=>t[n]||n)}async function mt(e,t){if(!t)return{};const n=t[A.AUTHORIZATION];if(!n)return{};try{const r=f.decode(n);if(r.header.alg===w.RS256){S.jwks[r.header.kid]===void 0&&await Le(e);const m=S.jwks[r.header.kid];if(!m)return S.jwks[r.header.kid]=null,{};await f.verify(n,m,w.RS256)}else await f.verify(n,C,w.HS256);const o=r.payload.idpId||S.jwks[r.header.kid]?.idpId,a=e[o]||{},s=Me(a),l=De(a);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...W(r.payload.teams||[],l),..."defaultTeams"in a&&a.defaultTeams||[],...W("teamsClaimName"in a&&r.payload[s||""]||[],l),re])),name:Oe(r.payload),isAuthenticated:!0,idpAccessToken:r.payload.idp_access_token||t[A.IDP_ACCESS_TOKEN],federatedAccessToken:t[A.FEDERATED_ACCESS_TOKEN],federatedIdToken:t[A.FEDERATED_ID_TOKEN],authCookie:n}}catch(r){r instanceof ie||ae.error("Malformed JWT token: %s",r.message)}return{}}function Oe(e){return(e.firstName&&e.lastName?`${e.firstName} ${e.lastName}`:e.name||e.given_name||e.firstName||e.lastName)||e.email}function De(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function Me(e){switch(e.type){case u.SAML2:return e.teamsAttributeName;case u.OIDC:return e.teamsClaimName;default:return Z}}function c(e,t){return q.select(t,e)||[]}export{ot as buildLoginUrl,he as buildOidcLoginUrl,et as buildOidcLogoutUrl,ge as buildSAML2LoginUrl,tt as createMcpAuthorizationCode,rt as createMcpSessionResource,at as decodeSamlResponse,_e as encodeSAML2,dt as extractUserClaims,Ze as getAuthProviderLoginParams,pe as getOidcLoginParams,F as getOidcMetadata,ct as getRedoclyTokenPayload,fe as getSaml2LoginParams,mt as getUserParamsFromCookies,Oe as getUsernameFromPayload,V as isOidcProviderConfig,ut as isRedoclySso,me as isSaml2ProviderConfig,Ge as oidcExchangeCodeForToken,S as oidcJwksCache,T as oidcMetadataCache,st as parseOidcState,ye as parsePreviewBranch,it as parseSamlResponse,$ as rewritePreviewAuthRedirectUri,nt as verifyMcpAuthorizationCode,lt as verifySAMLResponse};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ServerRoutes as c}from"../../constants/
|
|
1
|
+
import{ServerRoutes as c}from"../../constants/api.js";import{reporter as n}from"../tools/notifiers/reporter.js";import{logger as s}from"../tools/notifiers/logger.js";import{telemetry as p}from"../telemetry/index.js";import{installDevRoutes as f,installProdRoutes as v}from"./routes/index.js";import{createRouter as l}from"./router.js";import{readStaticAsset as u}from"./node-asset-reader.js";import{startHttpServer as d}from"./http.js";import{listenStore as S}from"./store-ws.js";import{ejectComponentDataHandler as D}from"./routes/eject.js";import{attachWsServer as R}from"./ws.js";import{DatabasePreconnectService as w}from"../providers/database/database-preconnect-service.js";import{KvService as g}from"../persistence/kv/services/kv-service.js";import{runScorecardsWorker as O}from"../plugins/scorecards/workers/run-scorecards-worker.js";import{isScorecardsEnabled as E}from"../utils/is-scorecards-enabled.js";import{isRealmOrReef as b}from"../utils/is-realm-or-reef.js";async function J(r,i,a){p.initialize(!0);const{port:m=4e3}=a,t=l();if(t.get(c.EJECT_COMPONENT,D(r)),f(t,r),v(t,r,{readStaticAsset:u,resolveRouteData:e=>r.resolveRouteStaticData(e,i)}),b()){await w.init(r.serverOutDir);const e=await g.getInstance({baseDbDir:r.serverOutDir});setInterval(()=>{e.clearExpired().catch(o=>{s.error("Failed to clear expired KV entries",o)})},300*1e3)}try{await r.userCodeReady;const e=await d(t,m),o=R(e);S(r,o),E(r.config)&&await O(r.serverOutDir,r.config.scorecards)}catch(e){await n.panic(e)}}export{J as startDevServer};
|