@redocly/realm 0.136.0-next.1 → 0.136.0-next.3
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 +29 -0
- package/dist/cli/eject/ejectComponent.d.ts +1 -1
- package/dist/cli/eject/ejectTheme.d.ts +1 -1
- package/dist/cli/eject/themeOperations.d.ts +2 -2
- package/dist/client/TestProvider.d.ts +1 -1
- package/dist/client/app/ConditionalLink.d.ts +1 -1
- package/dist/client/app/hooks/catalog/useCatalogFilter.d.ts +1 -1
- package/dist/client/app/hooks/catalog/useCatalogViewMode.js +1 -1
- package/dist/client/app/hooks/catalog/useFetchCatalogEntities.d.ts +1 -1
- package/dist/client/app/hooks/catalog/useFetchCatalogEntities.js +1 -1
- package/dist/client/app/hooks/catalog/useFetchCatalogEntitiesRelations.d.ts +2 -2
- package/dist/client/app/hooks/catalog/useFetchCatalogEntitiesRelations.js +1 -1
- package/dist/client/app/hooks/catalog/useFetchCatalogEntityRevisions.d.ts +1 -1
- package/dist/client/app/hooks/catalog/useSearchTracker.d.ts +2 -5
- package/dist/client/app/hooks/catalog/useSearchTracker.js +1 -1
- package/dist/client/app/hooks/codeHighlight/useCodeHighlight.d.ts +1 -6
- package/dist/client/app/pages/DevLogin/DevLoginForm.d.ts +1 -1
- package/dist/client/app/useGlobalData.d.ts +1 -1
- package/dist/client/app/utils/loadAndNavigate.d.ts +1 -1
- package/dist/client/providers/page-data/hooks.d.ts +2 -2
- package/dist/client/providers/post-message/use-post-message.d.ts +1 -1
- package/dist/markdoc/helpers/get-operation/get-operation.d.ts +1 -1
- package/dist/markdoc/tags/index.d.ts +48 -2
- package/dist/server/api-routes/helpers/read-stream-with-size-limit.d.ts +1 -1
- package/dist/server/api-routes/run-api-routes-worker.d.ts +1 -1
- package/dist/server/api-routes/run-api-routes-worker.js +1 -1
- package/dist/server/config/env-config.d.ts +2 -0
- package/dist/server/config/env-schema.d.ts +5 -0
- 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/persistence/cache/mappers/create-cache-db-record.d.ts +1 -1
- package/dist/server/persistence/file-hashes/mappers/create-file-hash-db-record.d.ts +1 -1
- package/dist/server/persistence/kv/mappers/create-kv-db-record.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/database/catalog-entities-diff-publisher.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/database/catalog-entities-revisions-pruner.d.ts +4 -2
- package/dist/server/plugins/catalog-entities/database/catalog-entities-revisions-pruner.js +23 -3
- package/dist/server/plugins/catalog-entities/database/catalog-entities-service.d.ts +5 -5
- package/dist/server/plugins/catalog-entities/database/mappers/create-entity-attributes-db-record.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/database/mappers/create-entity-db-record.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/database/mappers/create-entity-relation-db-record-from-file-schema.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/database/remote-publish-lock-service.d.ts +3 -3
- package/dist/server/plugins/catalog-entities/database/repositories/bffEntities/bff-entities-read-repository.d.ts +2 -2
- package/dist/server/plugins/catalog-entities/database/repositories/common/filters-repository.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/database/repositories/common/revision-repository.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-read-repository.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-write-repository.d.ts +2 -2
- package/dist/server/plugins/catalog-entities/database/repositories/entities/entities-write-repository.js +1 -1
- package/dist/server/plugins/catalog-entities/database/repositories/entityAttributes/entity-attributes-write-repository.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/database/repositories/relations/relations-read-repository.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.d.ts +5 -2
- package/dist/server/plugins/catalog-entities/extensions/extractors/api-description/base.js +1 -1
- package/dist/server/plugins/catalog-entities/extensions/extractors/fs-entities-extractor.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/plugin.js +1 -1
- package/dist/server/plugins/catalog-entities/utils/get-not-accessible-catalog-resources.d.ts +1 -1
- package/dist/server/plugins/catalog-entities/utils/openapi-component-content-extractor.d.ts +1 -1
- package/dist/server/plugins/dev-onboarding/index.d.ts +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/RevokeAPIKey.d.ts +1 -1
- package/dist/server/plugins/dev-onboarding/template/components/RollAPIKey.d.ts +1 -1
- package/dist/server/plugins/graphql-docs/search/ai/utils.d.ts +1 -1
- package/dist/server/plugins/markdown/markdoc/markdoc-options.d.ts +9 -9
- package/dist/server/plugins/markdown/markdoc/plugins/utils.d.ts +5 -0
- package/dist/server/plugins/markdown/markdoc/plugins/utils.js +1 -1
- package/dist/server/plugins/markdown/runtime-transform.js +1 -1
- package/dist/server/plugins/markdown/utils/resolve-markdown-template.d.ts +1 -1
- package/dist/server/plugins/mcp/auth/auth-handlers.d.ts +2 -0
- package/dist/server/plugins/mcp/auth/auth-handlers.js +1 -1
- package/dist/server/plugins/mcp/codemode/prompts.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tool-schemas.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/constants.d.ts +2 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/constants.js +1 -0
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-endpoint-info.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/get-security-schemes.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.d.ts +1 -1
- package/dist/server/plugins/mcp/docs-mcp/tools/openapi/utils.js +1 -1
- package/dist/server/plugins/mcp/docs-mcp/utils.d.ts +2 -2
- package/dist/server/plugins/mcp/gateway-mcp/fetch/fetch-bridge.d.ts +1 -1
- package/dist/server/plugins/mcp/servers/docs-server.d.ts +1 -1
- package/dist/server/plugins/mcp/workers/mcp-tool-telemetry.d.ts +2 -2
- package/dist/server/plugins/scorecard-classic/compute-scorecard.d.ts +1 -1
- package/dist/server/plugins/scorecard-classic/index.d.ts +1 -1
- package/dist/server/plugins/scorecard-classic/template/components.d.ts +1 -1
- package/dist/server/plugins/scorecard-classic/template/useData.d.ts +1 -1
- package/dist/server/plugins/search/ai-indexer/prepare-semantic-documents.d.ts +1 -1
- package/dist/server/plugins/search/engines/search-engine.d.ts +1 -1
- package/dist/server/plugins/search/llmstxt/index.d.ts +1 -1
- package/dist/server/plugins/sidebars/index.d.ts +1 -1
- package/dist/server/providers/database/database-path-generator.d.ts +2 -2
- package/dist/server/providers/database/utils/storage-limit-validator.d.ts +1 -1
- package/dist/server/sandbox/sandbox.js +2 -2
- package/dist/server/ssr/server-side-props/get-default-static-props.d.ts +1 -1
- package/dist/server/ssr/server-side-props/get-server-props-from-user-handler.d.ts +1 -1
- package/dist/server/ssr/template.d.ts +1 -1
- package/dist/server/store.js +1 -1
- package/dist/server/utils/sandbox-context.d.ts +18 -0
- package/dist/server/utils/sandbox-context.js +1 -0
- package/dist/server/web-server/auth.d.ts +1 -1
- package/dist/server/web-server/middleware/catalogAuthMiddleware.d.ts +1 -1
- package/dist/server/web-server/routes/auth.js +1 -1
- package/dist/server/web-server/routes/catalog/helpers/has-access-to-entity.d.ts +1 -1
- package/dist/server/web-server/routes/catalog/helpers/upsert-pages-stats.d.ts +1 -1
- package/dist/server/web-server/routes/feedback.d.ts +1 -1
- package/dist/server/web-server/routes/helpers/process-redirects.d.ts +1 -1
- package/dist/server/web-server/routes/mcp-routes/mcp-oauth.d.ts +5 -4
- 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/mcp-routes/utils/build-agent-card.d.ts +1 -1
- package/dist/server/web-server/utils/prepare-list-response.d.ts +1 -1
- package/dist/server/workers/api-routes-worker-pool.js +1 -1
- package/dist/server/workers/mcp-tool-worker-pool.js +1 -1
- package/dist/server/workers/worker-pool.d.ts +1 -0
- package/dist/server/workers/worker-pool.js +1 -1
- package/package.json +6 -6
|
@@ -7,7 +7,7 @@ type EndpointInfo = Pick<OpenAPIOperation, 'summary' | 'description' | 'security
|
|
|
7
7
|
path: string;
|
|
8
8
|
};
|
|
9
9
|
export declare function getEndpointsFromPaths(def: OpenAPIDefinition): EndpointInfo[];
|
|
10
|
-
export declare function getApiDescriptionFromFs({ relativePath, outdir, user, rbac, requiresLogin }: {
|
|
10
|
+
export declare function getApiDescriptionFromFs({ relativePath, outdir, user, rbac, requiresLogin, }: {
|
|
11
11
|
relativePath: string;
|
|
12
12
|
outdir: string;
|
|
13
13
|
user: ApiFunctionsUser;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import a from"node:path";import{existsSync as f}from"node:fs";import{readFile as d}from"node:fs/promises";import{replaceFileExtension as h}from"../../../../../plugins/openapi-docs/store-definition-bundles";import{PUBLIC_API_DEFINITIONS_FOLDER as
|
|
1
|
+
import a from"node:path";import{existsSync as f}from"node:fs";import{readFile as d}from"node:fs/promises";import{replaceFileExtension as h}from"../../../../../plugins/openapi-docs/store-definition-bundles";import{PUBLIC_API_DEFINITIONS_FOLDER as u}from"../../../../../constants/common";import{filterDataByAccessDeep as l}from"../../../../../utils/rbac";import{checkEndpointAndDeleteXMcp as c}from"../../../utils/xmcp-utils.js";import{OPERATION_METHODS as E}from"./constants.js";function T(t){return typeof t=="object"&&t!==null&&"responses"in t&&typeof t.responses=="object"}const D=new Set(E);function b(t){const{paths:n={}}=t,e=[];for(const[r,i]of Object.entries(n)){const s=!c(i,"docs");for(const[p,o]of Object.entries(i))D.has(p.toLowerCase())&&(s||!c(o,"docs")||e.push({path:r,method:p.toUpperCase(),summary:o.summary,description:o.description,security:o.security}))}return e}async function _({relativePath:t,outdir:n,user:e,rbac:r={},requiresLogin:i=!1}){const s=a.join(n||"",u,h(t,".json"));if(!f(s))return;const o=await d(s,"utf-8"),m=JSON.parse(o);return l(m,{isAuthenticated:e?.isAuthenticated,email:e?.email,teams:e?.teams},r,i)}export{_ as getApiDescriptionFromFs,b as getEndpointsFromPaths,T as isMcpEndpoint};
|
|
@@ -10,13 +10,13 @@ type ResolveSchemaRefsParams = {
|
|
|
10
10
|
maxDepth?: number;
|
|
11
11
|
currentDepth?: number;
|
|
12
12
|
};
|
|
13
|
-
export declare function resolveSchemaRefs({ schema, definition, visitedRefs, maxDepth, currentDepth }: ResolveSchemaRefsParams): OpenAPISchema | undefined;
|
|
13
|
+
export declare function resolveSchemaRefs({ schema, definition, visitedRefs, maxDepth, currentDepth, }: ResolveSchemaRefsParams): OpenAPISchema | undefined;
|
|
14
14
|
type ResolveParametersParams = {
|
|
15
15
|
pathParams: Referenced<OpenAPIParameter>[];
|
|
16
16
|
opParams: Referenced<OpenAPIParameter>[];
|
|
17
17
|
definition: OpenAPIDefinition;
|
|
18
18
|
};
|
|
19
|
-
export declare function resolveParameters({ pathParams, opParams, definition }: ResolveParametersParams): OpenAPIParameter[];
|
|
19
|
+
export declare function resolveParameters({ pathParams, opParams, definition, }: ResolveParametersParams): OpenAPIParameter[];
|
|
20
20
|
export declare function resolveRequestBody(requestBody: Referenced<OpenAPIRequestBody> | undefined, definition: OpenAPIDefinition): OpenAPIRequestBody | undefined;
|
|
21
21
|
export declare function resolveResponses(responses: Record<string, Referenced<OpenAPIResponse>>, definition: OpenAPIDefinition): Record<string, OpenAPIResponse>;
|
|
22
22
|
export {};
|
|
@@ -7,6 +7,6 @@ type FetchBridgeOptions = {
|
|
|
7
7
|
maxResponseBytes?: number;
|
|
8
8
|
};
|
|
9
9
|
/** Build the host-side `fetch` the gateway sandbox calls. */
|
|
10
|
-
export declare function buildFetchBridge({ allowedHosts, authorization, fetchImpl, timeoutMs, maxResponseBytes }: FetchBridgeOptions): SandboxFetch;
|
|
10
|
+
export declare function buildFetchBridge({ allowedHosts, authorization, fetchImpl, timeoutMs, maxResponseBytes, }: FetchBridgeOptions): SandboxFetch;
|
|
11
11
|
export {};
|
|
12
12
|
//# sourceMappingURL=fetch-bridge.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { McpToolSchema } from '../../../types';
|
|
2
2
|
import type { McpToolContext, SkillMcpResource } from '../types.js';
|
|
3
3
|
import { type McpServerInstance } from './mcp-server.js';
|
|
4
|
-
export declare function createDocsMcpServer({ name, tools, context, skills }: {
|
|
4
|
+
export declare function createDocsMcpServer({ name, tools, context, skills, }: {
|
|
5
5
|
name: string;
|
|
6
6
|
tools: McpToolSchema[];
|
|
7
7
|
context: McpToolContext;
|
|
@@ -5,10 +5,10 @@ type McpToolEvent = {
|
|
|
5
5
|
serverType: McpServerType;
|
|
6
6
|
durationMs: number;
|
|
7
7
|
};
|
|
8
|
-
export declare function reportMcpToolCalled({ tool, mode, serverType, durationMs, outputLength }: McpToolEvent & {
|
|
8
|
+
export declare function reportMcpToolCalled({ tool, mode, serverType, durationMs, outputLength, }: McpToolEvent & {
|
|
9
9
|
outputLength: number;
|
|
10
10
|
}): void;
|
|
11
|
-
export declare function reportMcpToolError({ tool, mode, serverType, durationMs, message, stack }: McpToolEvent & {
|
|
11
|
+
export declare function reportMcpToolError({ tool, mode, serverType, durationMs, message, stack, }: McpToolEvent & {
|
|
12
12
|
message: string;
|
|
13
13
|
stack?: string;
|
|
14
14
|
}): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LifecycleContext, ProcessContentActions } from '../../types';
|
|
2
2
|
import type { DetailedScorecardData } from './types.js';
|
|
3
3
|
import { type ScorecardConfig, type RedoclyConfig } from '@redocly/theme/config';
|
|
4
|
-
export declare function computeScorecard({ actions, context, scorecardConfig, reuniteConfig }: {
|
|
4
|
+
export declare function computeScorecard({ actions, context, scorecardConfig, reuniteConfig, }: {
|
|
5
5
|
actions: ProcessContentActions;
|
|
6
6
|
context: LifecycleContext;
|
|
7
7
|
scorecardConfig: ScorecardConfig;
|
|
@@ -5,7 +5,7 @@ export type ScorecardInfo = {
|
|
|
5
5
|
rules: string[];
|
|
6
6
|
rulesPerLevel: Record<string, string[]>;
|
|
7
7
|
};
|
|
8
|
-
export declare function scorecardClassicPlugin({ id, requiredEntitlements, loadersPrefix }: {
|
|
8
|
+
export declare function scorecardClassicPlugin({ id, requiredEntitlements, loadersPrefix, }: {
|
|
9
9
|
id?: string;
|
|
10
10
|
requiredEntitlements: Feature[];
|
|
11
11
|
loadersPrefix?: string;
|
|
@@ -4,7 +4,7 @@ export declare function ApiLevel({ level, colorVariable }: {
|
|
|
4
4
|
level: string;
|
|
5
5
|
colorVariable: string;
|
|
6
6
|
}): React.JSX.Element;
|
|
7
|
-
export declare function StatusDistribution({ summary }: {
|
|
7
|
+
export declare function StatusDistribution({ summary, }: {
|
|
8
8
|
summary: {
|
|
9
9
|
total: number;
|
|
10
10
|
levels: Record<string, number>;
|
|
@@ -40,7 +40,7 @@ export declare function useData(props: {
|
|
|
40
40
|
title: string;
|
|
41
41
|
items: CatalogItem[];
|
|
42
42
|
}[];
|
|
43
|
-
filters: import("@redocly/theme
|
|
43
|
+
filters: import("@redocly/theme").ResolvedFilter[];
|
|
44
44
|
scorecardInfo: {
|
|
45
45
|
levelNames: string[];
|
|
46
46
|
rulesPerLevel: Record<string, string[]>;
|
|
@@ -4,7 +4,7 @@ import type { AfterRoutesCreatedActions, AfterRoutesCreatedLifecycleContext } fr
|
|
|
4
4
|
* Chunking runs when any of these is enabled: AI search, llms.txt, or Docs MCP.
|
|
5
5
|
* embeddingsEnabled is true when AI search or Docs MCP is enabled (shared embedding index).
|
|
6
6
|
*/
|
|
7
|
-
export declare function prepareSemanticDocuments(actions: AfterRoutesCreatedActions, context: AfterRoutesCreatedLifecycleContext, { embeddingsEnabled, llmstxtEnabled }: {
|
|
7
|
+
export declare function prepareSemanticDocuments(actions: AfterRoutesCreatedActions, context: AfterRoutesCreatedLifecycleContext, { embeddingsEnabled, llmstxtEnabled, }: {
|
|
8
8
|
embeddingsEnabled: boolean;
|
|
9
9
|
llmstxtEnabled: boolean;
|
|
10
10
|
}): Promise<void>;
|
|
@@ -10,7 +10,7 @@ export declare class SearchEngine {
|
|
|
10
10
|
initIndexSchema(searchFacets: Map<string, SearchFacet>): Promise<void>;
|
|
11
11
|
addDocuments(documents: SearchDocument[], params: AddDocumentsParams): Promise<void>;
|
|
12
12
|
search(params: SearchRequestParams, auth: AuthDetails, facets?: Map<string, SearchFacet>): Promise<SearchResponse>;
|
|
13
|
-
countFacets(params: FacetCountsRequestParams, auth: AuthDetails, facets: Map<string, SearchFacet>): Promise<Record<string, import("@redocly/theme
|
|
13
|
+
countFacets(params: FacetCountsRequestParams, auth: AuthDetails, facets: Map<string, SearchFacet>): Promise<Record<string, import("@redocly/theme").SearchFacetCount[]>>;
|
|
14
14
|
export(outDir: string): Promise<void>;
|
|
15
15
|
import(sourceDir: string): Promise<void>;
|
|
16
16
|
cleanupFacetValues(actions: AfterRoutesCreatedActions): void;
|
|
@@ -5,7 +5,7 @@ export declare function generateLLMsTxt(llmstxts: LLMsTxt[], llmstxtConfig: SeoC
|
|
|
5
5
|
title?: string;
|
|
6
6
|
description?: string;
|
|
7
7
|
} | undefined, context: AfterRoutesCreatedLifecycleContext): Promise<string>;
|
|
8
|
-
export declare function llmsTxtLink({ title, description, slug }: {
|
|
8
|
+
export declare function llmsTxtLink({ title, description, slug, }: {
|
|
9
9
|
title: LLMsTxt['title'];
|
|
10
10
|
description: LLMsTxt['description'];
|
|
11
11
|
slug: LLMsTxt['slug'];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LifecyclePluginInstance, PluginOptions } from '../../types';
|
|
2
2
|
import type { ResolvedNavItem } from '@redocly/config';
|
|
3
3
|
import type { ContentFs } from '../../fs/content-fs.js';
|
|
4
|
-
export declare function sidebarsPlugin({ contentDir }: PluginOptions): Promise<LifecyclePluginInstance>;
|
|
4
|
+
export declare function sidebarsPlugin({ contentDir, }: PluginOptions): Promise<LifecyclePluginInstance>;
|
|
5
5
|
export declare function stripMarkdocFromDescriptions(items: ResolvedNavItem[]): void;
|
|
6
6
|
export declare function resolveSidebarId(relativePath: string, sidebarPath: string, fs: ContentFs): Promise<string | null>;
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -9,12 +9,12 @@ export declare class DatabasePathGenerator {
|
|
|
9
9
|
* Generate database path without any file system operations
|
|
10
10
|
* This is a pure function that can be used synchronously
|
|
11
11
|
*/
|
|
12
|
-
static generateDatabasePath({ baseDir, databaseName, additionalFolder }: DatabasePathOptions): string;
|
|
12
|
+
static generateDatabasePath({ baseDir, databaseName, additionalFolder, }: DatabasePathOptions): string;
|
|
13
13
|
/**
|
|
14
14
|
* Prepare database path with file system operations
|
|
15
15
|
* This handles directory creation and cleanup
|
|
16
16
|
*/
|
|
17
|
-
static prepareDatabasePath({ baseDir, databaseName, additionalFolder, removeExisting }: DatabasePathOptions & {
|
|
17
|
+
static prepareDatabasePath({ baseDir, databaseName, additionalFolder, removeExisting, }: DatabasePathOptions & {
|
|
18
18
|
removeExisting?: boolean;
|
|
19
19
|
}): Promise<{
|
|
20
20
|
databasePath: string;
|
|
@@ -7,7 +7,7 @@ type StorageLimitValidationParams = {
|
|
|
7
7
|
};
|
|
8
8
|
export declare class StorageLimitValidator {
|
|
9
9
|
#private;
|
|
10
|
-
validate({ storageLimitGb, currentTotalBytes, existingEntryBytes, incomingEntryBytes, errorMessagePrefix }: StorageLimitValidationParams): void;
|
|
10
|
+
validate({ storageLimitGb, currentTotalBytes, existingEntryBytes, incomingEntryBytes, errorMessagePrefix, }: StorageLimitValidationParams): void;
|
|
11
11
|
}
|
|
12
12
|
export {};
|
|
13
13
|
//# sourceMappingURL=storage-limit-validator.d.ts.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
1
|
+
import p from"@jitl/quickjs-singlefile-mjs-release-sync";import{newQuickJSWASMModuleFromVariant as S}from"quickjs-emscripten-core";import{createExecutionBudget as E}from"./utils/execution-budget.js";import{DEFAULT_MAX_LIFETIME_MS as g,DEFAULT_TIMEOUT_MS as T,MAX_RESULT_BYTES as _,MAX_STACK_SIZE_BYTES as y,MEMORY_LIMIT_BYTES as h}from"./constants/sandbox.js";let d;function x(){return d??=S(p)}async function R(t,c={}){const{timeoutMs:l=T,maxLifetimeMs:m=g,setupContext:f}=c,e=(await x()).newContext();let n,s,r;try{e.runtime.setMemoryLimit(h),e.runtime.setMaxStackSize(y),n=E(e,l,m),s=f?.(e,n)??void 0,r=e.unwrapResult(e.evalCode(`(async () => {
|
|
2
2
|
${t}
|
|
3
|
-
})()`));const
|
|
3
|
+
})()`));const i=e.resolvePromise(r);e.runtime.executePendingJobs();const M=await Promise.race([i,n.aborted]),u=e.unwrapResult(M),o=e.dump(u);if(u.dispose(),o===void 0)return{error:"The code returned undefined. Check that a top-level `return` yields a defined value: return the value directly (not `return;` or `return undefined`), read an existing field (a wrong field name is undefined), and do not wrap the logic in a function or IIFE whose return value is discarded."};const a=JSON.stringify(o??null).length;return a>_?{error:`Result is too large (${a} bytes); return less data`}:{result:o}}catch(i){return{error:v(i)}}finally{n?.dispose(),r?.dispose();try{s?.()}catch{}try{e.dispose()}catch{d=void 0}}}function v(t){return t instanceof Error?t.message:String(t)}export{R as runInSandbox};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PageStaticData } from '@redocly/config';
|
|
2
|
-
export declare function getDefaultStaticProps({ staticData, variables }: {
|
|
2
|
+
export declare function getDefaultStaticProps({ staticData, variables, }: {
|
|
3
3
|
staticData: PageStaticData;
|
|
4
4
|
variables: Record<string, unknown>;
|
|
5
5
|
}): {
|
|
@@ -9,7 +9,7 @@ export type ServerPropsResult = PageProps | {
|
|
|
9
9
|
stack?: string;
|
|
10
10
|
};
|
|
11
11
|
};
|
|
12
|
-
export declare function getServerPropsFromUserHandler({ route, ctx, staticData, serverPropsGetters, serverPropsUser, actions }: {
|
|
12
|
+
export declare function getServerPropsFromUserHandler({ route, ctx, staticData, serverPropsGetters, serverPropsUser, actions, }: {
|
|
13
13
|
route: PageRouteDetails;
|
|
14
14
|
ctx: Context | null;
|
|
15
15
|
staticData: PageStaticData;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RenderTemplateInput } from '../../types/index.js';
|
|
2
|
-
export declare function htmlTemplate({ bodyHtml, linkTags, title, favicon, preload, headScriptTags, postBodyScriptTags, preBodyScriptTags, lang, productClass, fonts, runtimeCss }: RenderTemplateInput & {
|
|
2
|
+
export declare function htmlTemplate({ bodyHtml, linkTags, title, favicon, preload, headScriptTags, postBodyScriptTags, preBodyScriptTags, lang, productClass, fonts, runtimeCss, }: RenderTemplateInput & {
|
|
3
3
|
fonts?: string;
|
|
4
4
|
}): string;
|
|
5
5
|
//# sourceMappingURL=template.d.ts.map
|
package/dist/server/store.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import C from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as O}from"./constants/common.js";import{GATED_MARKDOC_TAGS as D}from"./constants/entitlements.js";import{MARKDOC_PARTIALS_DATA_KEY as m,MARKDOC_PARTIALS_DEPS_KEY as T}from"./constants/common.js";import{isObject as M}from"../utils/guards/is-object.js";import{mapObject as k}from"../utils/object/map-object.js";import{getValueDeep as y}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as L}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as h}from"../utils/path/normalize-route-slug.js";import{isLocalLink as R}from"../utils/path/is-local-link.js";import{reporter as S}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as H}from"./utils/crypto/sha1.js";import{envConfig as _,setEnv as G}from"./config/env-config.js";import{KvService as B}from"./persistence/kv/services/kv-service.js";import{writeSharedData as F}from"./utils/index.js";import{renderComponents as I}from"./ssr/render.js";import{readStaticData as N,writeStaticData as q}from"./utils/static-data.js";import{parseAndResolveMarkdoc as V}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as j}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as w}from"./entitlements/entitlements-provider.js";import{isL10nPath as U}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as K}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{followRedirectChain as W}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as $}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as z}from"../cli/telemetry/helpers/trace-step.js";const v={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map"},E="PLAN_GATES",Y=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Oe="userDefinedApiFunctions";class P{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;mcpToolHandlers=new Map;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#o=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#u=Promise.resolve();#h;#e=!1;#r=0;#f=0;#a=new Map;constructor({outdir:e,contentDir:t,serverMode:s=!1,serverOutDir:a}){this.#i=t,this.outdir=e,this.serverMode=s,this.serverOutDir=a,this.userCodeReady=new Promise(r=>{this.#n=r})}on(e,t){const s=this.listeners.get(e);s?s.add(t):this.listeners.set(e,new Set([t]))}queueEvent=(e,t,...s)=>{this.#a.set(e+String(t),[e,t,...s])};runListeners=(e,t,...s)=>{for(const a of this.listeners.get(e)||new Set)t?a(t,...s):a(...s)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#u])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#a.values())this.runListeners(...e);this.#a.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#u=new Promise(e=>{this.#h=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#h?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await z("build.reload_markdoc_options",async()=>{const e=w.instance(),t=await j(this.serverOutDir),s=Object.fromEntries(Object.entries(t.tags).filter(([a])=>D[a]!=null?e.canAccessFeature(D[a]):!0));this.#o={...t,tags:s}})}get markdocOptions(){return{...this.#o,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const t=this.globalData,s={...this.globalData,...e};this.globalData=s,JSON.stringify(s)!==JSON.stringify(t)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>B.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:t,deps:s,resource:a})=>{const{data:{info:r,ast:o},compoundHash:l}=await V(e,this.markdocOptions,{actions:this,context:t},a);for(const i of r.sharedDataDeps||[]){for(const n of s?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of s?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(i),this.sharedDataDeps.set(n,c)}}for(const i of r.dynamicMarkdocComponents||[]){for(const n of s?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(i),this.routesDynamicComponents.set(n,c)}for(const n of s?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(n,c)}}if(s?.routeSlugs&&r.partials?.length)for(const i of s.routeSlugs){const n=this.routesPartials.get(i)||[];for(const c of r.partials)n.includes(c)||n.push(c);this.routesPartials.set(i,n)}return{info:r,ast:o,compoundHash:l}};async loadOpenApiDefinitions(e){return(await e.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(e){return(await e.cache.load(".","asyncapi-docs")).data}async loadGraphqlDefinitions(e){return(await e.cache.load(".","load-graphql-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setGlobalConfig=e=>{const t=Object.keys(e);for(const o of t)for(const l in this.replacedEnvVars)if(l===o||l.startsWith(`${o}:`)){const i=l.split(":"),{error:n,value:c}=y(e,i);(n||c!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:s,unsetEnvVars:a,replacedValues:r}=J(e);for(const o of a)this.unsetEnvVars.add(o);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,t,s={})=>{if(!w.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const o=h(e).toLowerCase();this.config.redirects[o]=t;const{trackOriginalSource:l=!0}=s,i=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(i)&&!i.includes(o)&&i.push(o),o.endsWith("*")&&$(this.config.wildcardRedirectsTree,o)};getRedirect=e=>{const t=h(e).toLowerCase(),s=x(t,this.config.redirects,this.config.wildcardRedirectsTree);if(!s)return null;if(R(s.to)){const a=h(s.to).toLowerCase();if(!a.endsWith("*")&&W(a,[t],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:s.to,type:s.type}};createSharedData=async(e,t,s)=>{if(s&&this.#t[e]===s)return e;const a=JSON.stringify(t),r=s??H(a);return this.#t[e]===r||(this.#t[e]=r,await F(e,a,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,t,s)=>{const a=L(e),r=this.routesSharedData.get(a)||{};r[t]=s,this.routesSharedData.set(a,r),u.verbose(`Adding shared data to ${e}, ${t}, ${s}`)};getRouteSharedDataByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.routesSharedData.get(t)||{}:{}};getPartialsForRoute=e=>{const t=this.getGlobalConfig(m)||{},s=this.routesPartials.get(e);if(!s||s.length===0)return{};const a=this.getGlobalConfig(T)||{},r=new Set(s),o=Array.from(s);for(let i=0;i<o.length;i++){const n=o[i],c=a[n]?.partials??[];for(const d of c)r.has(d)||(r.add(d),o.push(d))}const l={};for(const i of r)t[i]&&(l[i]=t[i]);return l};addRoute=e=>{const s={...K(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:s}),u.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,t,s)=>{const a=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const o=A(e,g,r.code,a);this.addRouteSharedData(o,t,s)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,t)=>{for(const s of t)this.mcpToolHandlers.set(s.name,{...s,importPath:e}),u.verbose("Created MCP tool %s",s.name)};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());addSkills=e=>{for(const t of e)this.skills.set(t.slug,t),u.verbose("Discovered skill %s",t.slug)};getSkills=()=>Array.from(this.skills.values());addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,t)=>{this.config.responseHeaders||(this.config.responseHeaders={});const s=new Set(t.map(o=>o.name.toLowerCase())),r=[...(this.config.responseHeaders[e]??[]).filter(o=>!s.has(o.name.toLowerCase())),...t];this.config.responseHeaders[e]=r};getRouteByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.getRouteBySlug(t):void 0};getRouteBySlug=(e,t={})=>{const{followRedirect:s=!0}=t,a=this.getRedirect(e);return s&&a?this.routesBySlug.get(h(a.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e))return!0;const t=this.getRedirect(e);if(!t)return!1;if(!R(t.to))return!0;const s=h(t.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=e=>this.newRoutes.filter(t=>t.templateId===e);getAllRoutesForLocale=(e=g)=>{const t=Array.from(this.routesBySlug.values()),s=e.toLowerCase();return t.filter(a=>e===g?!U(a.fsPath):a.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,t)=>(this.templates.set(e,t),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,t)=>(this.apiRoutesRequestHandlers.set(e,t),e);clearRequestHandlersByPrefix=e=>{for(const t of this.apiRoutesRequestHandlers.keys())t.startsWith(e)&&this.apiRoutesRequestHandlers.delete(t)};registerServerPropsGetter=(e,t)=>(this.serverPropsGetters.set(e,t),e);registerPagePropsGetter=(e,t)=>{this.pagePropsGetters.set(e,t)};async writeRouteStaticData(e,t){const s=await this.resolveRouteStaticData(e,t,!1);s&&q(e.slug,s,this.outdir)}async resolveRouteStaticData(e,t,s){if(this.serverMode)return N(e.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},r=await e.getStaticData?.(e,a)||{},o=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>o.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const i=this.getGlobalConfig("seo"),n=r?.frontmatter||{};return{...r,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(o),metadata:{...r?.props?.metadata,...e.metadata},seo:{title:O,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:s||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,t){if(!e?.length)return;const s=typeof e[0]=="string"?e.join(""):I(e);s&&(t==="head"?this.ssr.headTags.push(s):t==="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.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[s,a]of Object.entries(v))switch(a){case"map":const r=Array.from(this[s].entries());e.push([s,r]);break;case"object":s==="config"&&e.push([s,await this.getConfigWithEnvPlaceholders()]),e.push([s,this[s]]);break;default:throw new Error("Invalid format")}const t=Object.fromEntries(e);return t[E]=_.PLAN_GATES,t}static fromJson(e,t){const s=new P(t);for(const[r,o]of Object.entries(v))switch(o){case"map":s[r]=new Map(e[r]);break;case"object":if(r==="config"){s.setGlobalConfig(e[r]);break}s[r]=e[r];break;default:throw new Error("Invalid format")}s.config[m]=Z(s.config[m]||{});const a=e[E];return a&&G("PLAN_GATES",a),s}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const t in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[t],a=t.split(":"),r=a.pop(),{error:o,value:l}=y(e,a);if(o||!M(l)&&!Array.isArray(l)){await S.panicOnBuild(`Failed to replace env var with env name for ${t}`);continue}l[r]=s}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(s=>!Y.includes(s));if(e.length===0)return;const t=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await S.panicOnBuildContentError(t)}}function Z(b){return k(b,e=>C.Ast.fromJSON(JSON.stringify(e)))}export{P as Store,Oe as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
|
|
1
|
+
import C from"@markdoc/markdoc";import{getPathnameForLocale as A}from"@redocly/theme/core/utils";import{DEFAULT_LOCALE_PLACEHOLDER as g}from"../constants/common.js";import{DEFAULT_TITLE as T}from"./constants/common.js";import{GATED_MARKDOC_TAGS as y}from"./constants/entitlements.js";import{MARKDOC_PARTIALS_DATA_KEY as m,MARKDOC_PARTIALS_DEPS_KEY as O}from"./constants/common.js";import{isObject as M}from"../utils/guards/is-object.js";import{mapObject as k}from"../utils/object/map-object.js";import{getValueDeep as D}from"../utils/object/get-value-deep.js";import{removeTrailingSlash as L}from"../utils/url/remove-trailing-slash.js";import{normalizeRouteSlug as h}from"../utils/path/normalize-route-slug.js";import{isLocalLink as R}from"../utils/path/is-local-link.js";import{reporter as S}from"./tools/notifiers/reporter.js";import{logger as u}from"./tools/notifiers/logger.js";import{sha1 as H}from"./utils/crypto/sha1.js";import{envConfig as _,setEnv as G}from"./config/env-config.js";import{KvService as B}from"./persistence/kv/services/kv-service.js";import{SandboxContext as F}from"./utils/sandbox-context.js";import{writeSharedData as I}from"./utils/index.js";import{renderComponents as N}from"./ssr/render.js";import{readStaticData as q,writeStaticData as V}from"./utils/static-data.js";import{parseAndResolveMarkdoc as j}from"./plugins/markdown/compiler.js";import{getMarkdocOptions as U}from"./plugins/markdown/markdoc/markdoc-options.js";import{EntitlementsProvider as w}from"./entitlements/entitlements-provider.js";import{isL10nPath as K}from"./fs/utils/is-l10n-path.js";import{resolveGlobMapValue as x}from"./utils/globs.js";import{replaceEnvVariablesDeep as J}from"./utils/envs/replace-env-variables-deep.js";import{findRedirect as W}from"./utils/redirects/find-redirect.js";import{followRedirectChain as $}from"./utils/redirects/follow-redirect-chain.js";import{addWildcardRedirectToTree as z}from"./utils/redirects/add-wildcard-redirect-to-tree.js";import{telemetryTraceStep as Y}from"../cli/telemetry/helpers/trace-step.js";const v={routesBySlug:"map",apiRoutes:"object",middleware:"object",routesByFsPath:"map",routesSharedData:"map",globalData:"object",config:"object",ssr:"object",searchFacets:"map",routesPartials:"map",mcpToolHandlers:"map",skills:"map"},E="PLAN_GATES",Z=["OAUTH_CLIENT_ID","OAUTH_CLIENT_SECRET","ORGANIZATION_SLUG","ORGANIZATION_ID","ORG_ID"],Me="userDefinedApiFunctions";class P{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;mcpToolHandlers=new Map;skills=new Map;serverPropsGetters=new Map;pagePropsGetters=new Map;listeners=new Map;globalData={};#o=void 0;config={configFilePath:"",redirects:{},wildcardRedirectsTree:{},access:{rbac:{},requiresLogin:!1},directoryPermissions:{},devLogin:!1,ssoDirect:{}};#i;serverMode;serverOutDir;outdir;buildRevision=0;hasSitemap=!1;compilationErrors=[];#n;userCodeReady;#s=Promise.resolve();#c;#l=Promise.resolve();#d;#u=Promise.resolve();#h;#e=!1;#r=0;#f=0;#a=new Map;constructor({outdir:e,contentDir:t,serverMode:s=!1,serverOutDir:a}){this.#i=t,this.outdir=e,this.serverMode=s,this.serverOutDir=a,F.register({serverOutDir:a,readRoots:[e,process.cwd()]}),this.userCodeReady=new Promise(r=>{this.#n=r})}on(e,t){const s=this.listeners.get(e);s?s.add(t):this.listeners.set(e,new Set([t]))}queueEvent=(e,t,...s)=>{this.#a.set(e+String(t),[e,t,...s])};runListeners=(e,t,...s)=>{for(const a of this.listeners.get(e)||new Set)t?a(t,...s):a(...s)};startPluginsRun(){this.clear(),this.#s=new Promise(e=>{this.#c=e})}waitForPluginsLifecycle(){return Promise.all([this.#s,this.#l,this.#u])}waitForPluginsRun(){return this.#s}finishPluginsRun(){this.#c?.();for(const e of this.#a.values())this.runListeners(...e);this.#a.clear()}startEsbuildRun(){this.#l=new Promise(e=>{this.#d=e})}finishEsbuildRun(){this.#d?.()}markRequestHandlersEntryOutdated(){this.#r++,!this.#e&&(this.#e=!0,this.#u=new Promise(e=>{this.#h=e}))}noteRequestHandlersEntryBuildStart(){this.#f=this.#r}markRequestHandlersEntryUpdated(){this.#e&&(this.#r>this.#f||(this.#e=!1,this.#h?.()))}get contentDir(){if(this.serverMode)throw new Error("contentDir should not be used in server mode");return this.#i}markUserCodeReady(){this.#n?.(!0)}async reloadMarkdocOptions(){await Y("build.reload_markdoc_options",async()=>{const e=w.instance(),t=await U(this.serverOutDir),s=Object.fromEntries(Object.entries(t.tags).filter(([a])=>y[a]!=null?e.canAccessFeature(y[a]):!0));this.#o={...t,tags:s}})}get markdocOptions(){return{...this.#o,partials:this.getGlobalConfig(m),themeConfig:this.config.markdown}}setGlobalData=e=>{const t=this.globalData,s={...this.globalData,...e};this.globalData=s,JSON.stringify(s)!==JSON.stringify(t)&&this.queueEvent("global-data-updated",void 0,s)};getGlobalData=()=>this.globalData;getKv=async()=>B.getInstance({baseDbDir:this.serverOutDir});parseMarkdoc=async({input:e,context:t,deps:s,resource:a})=>{const{data:{info:r,ast:o},compoundHash:l}=await j(e,this.markdocOptions,{actions:this,context:t},a);for(const i of r.sharedDataDeps||[]){for(const n of s?.routeSlugs||[])this.addRouteSharedData(n,i,i);for(const n of s?.sharedDataIds||[]){const c=this.sharedDataDeps.get(n)||new Set;c.add(i),this.sharedDataDeps.set(n,c)}}for(const i of r.dynamicMarkdocComponents||[]){for(const n of s?.routeSlugs||[]){const c=this.routesDynamicComponents.get(n)||new Set;c.add(i),this.routesDynamicComponents.set(n,c)}for(const n of s?.sharedDataIds||[]){const c=this.sharedDataMarkdocComponents.get(n)||new Set;c.add(i),this.sharedDataMarkdocComponents.set(n,c)}}if(s?.routeSlugs&&r.partials?.length)for(const i of s.routeSlugs){const n=this.routesPartials.get(i)||[];for(const c of r.partials)n.includes(c)||n.push(c);this.routesPartials.set(i,n)}return{info:r,ast:o,compoundHash:l}};async loadOpenApiDefinitions(e){return(await e.cache.load(".","load-oas-docs")).data}async loadAsyncApiDefinitions(e){return(await e.cache.load(".","asyncapi-docs")).data}async loadGraphqlDefinitions(e){return(await e.cache.load(".","load-graphql-docs")).data}setSearchEngine(e){this.searchEngine=e}setSearchFacets=e=>{this.searchFacets=e};setGlobalConfig=e=>{const t=Object.keys(e);for(const o of t)for(const l in this.replacedEnvVars)if(l===o||l.startsWith(`${o}:`)){const i=l.split(":"),{error:n,value:c}=D(e,i);(n||c!==this.replacedEnvVars[l].replaced)&&delete this.replacedEnvVars[l]}const{resolvedObj:s,unsetEnvVars:a,replacedValues:r}=J(e);for(const o of a)this.unsetEnvVars.add(o);Object.assign(this.replacedEnvVars,r),Object.assign(this.config,s)};getConfig=()=>this.config;getGlobalConfig=e=>this.config[e];getSearchFacets=()=>this.searchFacets;addRedirect=(e,t,s={})=>{if(!w.instance().canAccessFeature("redirects")&&e!=="/")return;this.config.redirects||(this.config.redirects={});const o=h(e).toLowerCase();this.config.redirects[o]=t;const{trackOriginalSource:l=!0}=s,i=this.getGlobalConfig("originalRedirectSources");l&&Array.isArray(i)&&!i.includes(o)&&i.push(o),o.endsWith("*")&&z(this.config.wildcardRedirectsTree,o)};getRedirect=e=>{const t=h(e).toLowerCase(),s=W(t,this.config.redirects,this.config.wildcardRedirectsTree);if(!s)return null;if(R(s.to)){const a=h(s.to).toLowerCase();if(!a.endsWith("*")&&$(a,[t],this.config.redirects,this.config.wildcardRedirectsTree).type==="cycle")return null}return{to:s.to,type:s.type}};createSharedData=async(e,t,s)=>{if(s&&this.#t[e]===s)return e;const a=JSON.stringify(t),r=s??H(a);return this.#t[e]===r||(this.#t[e]=r,await I(e,a,this.outdir),this.queueEvent("shared-data-updated",e)),e};addRouteSharedData=(e,t,s)=>{const a=L(e),r=this.routesSharedData.get(a)||{};r[t]=s,this.routesSharedData.set(a,r),u.verbose(`Adding shared data to ${e}, ${t}, ${s}`)};getRouteSharedDataByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.routesSharedData.get(t)||{}:{}};getPartialsForRoute=e=>{const t=this.getGlobalConfig(m)||{},s=this.routesPartials.get(e);if(!s||s.length===0)return{};const a=this.getGlobalConfig(O)||{},r=new Set(s),o=Array.from(s);for(let i=0;i<o.length;i++){const n=o[i],c=a[n]?.partials??[];for(const d of c)r.has(d)||(r.add(d),o.push(d))}const l={};for(const i of r)t[i]&&(l[i]=t[i]);return l};addRoute=e=>{const s={...x(e.fsPath,this.config.metadataGlobs),...e.metadata||{}};this.newRoutes.push({...e,metadata:s}),u.verbose("Created route %s",e.slug)};addRouteSharedDataToAllLocales=(e,t,s)=>{const a=[g,...this.lifecycleContext?.fs.localeFolders||[]].map(r=>({code:r,name:r}));for(const r of a){const o=A(e,g,r.code,a);this.addRouteSharedData(o,t,s)}};addApiRoute=e=>{this.apiRoutes.push(e),u.verbose("Created API route %s",e.slug)};addMcpTools=(e,t)=>{for(const s of t)this.mcpToolHandlers.set(s.name,{...s,importPath:e}),u.verbose("Created MCP tool %s",s.name)};getMcpTools=()=>Array.from(this.mcpToolHandlers.values());addSkills=e=>{for(const t of e)this.skills.set(t.slug,t),u.verbose("Discovered skill %s",t.slug)};getSkills=()=>Array.from(this.skills.values());addMiddleware=e=>{this.middleware.push(e),u.verbose("Created middleware %s",e.id)};setResourceResponseHeaders=(e,t)=>{this.config.responseHeaders||(this.config.responseHeaders={});const s=new Set(t.map(o=>o.name.toLowerCase())),r=[...(this.config.responseHeaders[e]??[]).filter(o=>!s.has(o.name.toLowerCase())),...t];this.config.responseHeaders[e]=r};getRouteByFsPath=e=>{const t=this.routesByFsPath.get(e);return t?this.getRouteBySlug(t):void 0};getRouteBySlug=(e,t={})=>{const{followRedirect:s=!0}=t,a=this.getRedirect(e);return s&&a?this.routesBySlug.get(h(a.to)):this.routesBySlug.get(e)};hasRouteOrRedirectBySlug=e=>{if(this.routesBySlug.has(e))return!0;const t=this.getRedirect(e);if(!t)return!1;if(!R(t.to))return!0;const s=h(t.to);return this.routesBySlug.has(s)};getRoutesByTemplateId=e=>this.newRoutes.filter(t=>t.templateId===e);getAllRoutesForLocale=(e=g)=>{const t=Array.from(this.routesBySlug.values()),s=e.toLowerCase();return t.filter(a=>e===g?!K(a.fsPath):a.slug.startsWith(`/${s}`))};getAllRoutes=()=>Array.from(this.routesBySlug.values());getAllApiRoutes=()=>this.apiRoutes;getAllMiddleware=()=>this.middleware;getTemplate=e=>this.templates.get(e);getRequestHandler=e=>this.apiRoutesRequestHandlers.get(e);createTemplate=(e,t)=>(this.templates.set(e,t),e);addBrowserPlugin=e=>{this.browserPlugins.add(e)};createRequestHandler=(e,t)=>(this.apiRoutesRequestHandlers.set(e,t),e);clearRequestHandlersByPrefix=e=>{for(const t of this.apiRoutesRequestHandlers.keys())t.startsWith(e)&&this.apiRoutesRequestHandlers.delete(t)};registerServerPropsGetter=(e,t)=>(this.serverPropsGetters.set(e,t),e);registerPagePropsGetter=(e,t)=>{this.pagePropsGetters.set(e,t)};async writeRouteStaticData(e,t){const s=await this.resolveRouteStaticData(e,t,!1);s&&V(e.slug,s,this.outdir)}async resolveRouteStaticData(e,t,s){if(this.serverMode)return q(e.slug,this.outdir);const a={...this,contentDir:this.contentDir,parseMarkdoc:({input:c,context:d,resource:f})=>this.parseMarkdoc({input:c,context:d,deps:{routeSlugs:[e.slug]},resource:f})},r=await e.getStaticData?.(e,a)||{},o=new Set(this.routesDynamicComponents.get(e.slug)),l=this.routesSharedData.get(e.slug)||{};for(const c of Object.values(l)){const d=this.sharedDataMarkdocComponents.get(c);d&&d.forEach(p=>o.add(p));const f=this.sharedDataDeps.get(c);f&&f.forEach(p=>this.addRouteSharedData(e.slug,p,p))}const i=this.getGlobalConfig("seo"),n=r?.frontmatter||{};return{...r,frontmatter:{...n,seo:{...n?.seo,title:n?.seo?.title||await e.getNavText?.()}},props:{...r.props,dynamicMarkdocComponents:Array.from(o),metadata:{...r?.props?.metadata,...e.metadata},seo:{title:T,...i,...r.props?.seo},compilationErrors:this.compilationErrors},lastModified:s||!e.fsPath?null:await this.lifecycleContext?.fs.getLastModified(e.fsPath)}}addSsrComponents(e,t){if(!e?.length)return;const s=typeof e[0]=="string"?e.join(""):N(e);s&&(t==="head"?this.ssr.headTags.push(s):t==="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.skills.clear(),this.config.redirects={},this.config.wildcardRedirectsTree={},this.config.directoryPermissions={},this.ssr={preBodyTags:[],postBodyTags:[],headTags:[]}};async toJson(){const e=[];for(const[s,a]of Object.entries(v))switch(a){case"map":const r=Array.from(this[s].entries());e.push([s,r]);break;case"object":s==="config"&&e.push([s,await this.getConfigWithEnvPlaceholders()]),e.push([s,this[s]]);break;default:throw new Error("Invalid format")}const t=Object.fromEntries(e);return t[E]=_.PLAN_GATES,t}static fromJson(e,t){const s=new P(t);for(const[r,o]of Object.entries(v))switch(o){case"map":s[r]=new Map(e[r]);break;case"object":if(r==="config"){s.setGlobalConfig(e[r]);break}s[r]=e[r];break;default:throw new Error("Invalid format")}s.config[m]=Q(s.config[m]||{});const a=e[E];return a&&G("PLAN_GATES",a),s}async getConfigWithEnvPlaceholders(){const e=JSON.parse(JSON.stringify(this.config));for(const t in this.replacedEnvVars){const{original:s}=this.replacedEnvVars[t],a=t.split(":"),r=a.pop(),{error:o,value:l}=D(e,a);if(o||!M(l)&&!Array.isArray(l)){await S.panicOnBuild(`Failed to replace env var with env name for ${t}`);continue}l[r]=s}return e}async reportUnsetEnvVars(){if(this.unsetEnvVars.size===0)return;const e=Array.from(this.unsetEnvVars).filter(s=>!Z.includes(s));if(e.length===0)return;const t=`Failed to resolve config. The following environment variables are not set: ${e.join(", ")}`;await S.panicOnBuildContentError(t)}}function Q(b){return k(b,e=>C.Ast.fromJSON(JSON.stringify(e)))}export{P as Store,Me as USER_DEFINED_API_FUNCTIONS_COUNTER_KEY};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare class SandboxContext {
|
|
2
|
+
#private;
|
|
3
|
+
readonly serverOutDir: string;
|
|
4
|
+
static register({ serverOutDir, readRoots, }: {
|
|
5
|
+
serverOutDir: string;
|
|
6
|
+
readRoots?: string[];
|
|
7
|
+
}): void;
|
|
8
|
+
static resolve(fallbackServerOutDir: string): SandboxContext;
|
|
9
|
+
private constructor();
|
|
10
|
+
get tmpDir(): string;
|
|
11
|
+
get execArgv(): string[];
|
|
12
|
+
get env(): {
|
|
13
|
+
TMPDIR: string;
|
|
14
|
+
TMP: string;
|
|
15
|
+
TEMP: string;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=sandbox-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as a}from"node:fs";import{dirname as l,join as m}from"node:path";class s{serverOutDir;static#e;static register({serverOutDir:e,readRoots:t}){s.#e=new s(e,t)}static resolve(e){return s.#e??new s(e)}#t;constructor(e,t=[]){this.serverOutDir=e,this.#t=s.#n(e,t)}get tmpDir(){return`${this.serverOutDir}/.data/tmp`}get execArgv(){return["--permission",...this.#t.map(e=>`--allow-fs-read=${e}/*`),`--allow-fs-write=${this.serverOutDir}/.data/*`,"--allow-addons"]}get env(){return{TMPDIR:this.tmpDir,TMP:this.tmpDir,TEMP:this.tmpDir}}static#r(e){if(!e)return e;const r=e.indexOf("/node_modules/");return r!==-1?e.slice(0,r):s.#s(e)??s.#i(e)??e}static#s(e){let t=e;for(;;){if(a(m(t,"node_modules",".pnpm")))return t;const r=l(t);if(r===t)return;t=r}}static#i(e){let t=e;for(;;){if(a(m(t,"node_modules")))return t;const r=l(t);if(r===t)return;t=r}}static#n(e,t){const r=[s.#r(e),...t].filter(Boolean).map(i=>i.replace(/\/+$/,"")).filter(Boolean),n=[...new Set(r)];return n.filter(i=>!n.some(o=>o!==i&&i.startsWith(`${o}/`)))}}export{s as SandboxContext};
|
|
@@ -41,7 +41,7 @@ export declare function oidcExchangeCodeForToken(tokenUrl: string, code: string,
|
|
|
41
41
|
error?: string;
|
|
42
42
|
error_description?: string;
|
|
43
43
|
}>;
|
|
44
|
-
export declare function buildOidcLoginUrl(origin: string, { authorizationEndpoint, clientId, responseType, scope, extraParams, idpId, pkce }: Partial<OidcLoginParams>, redirectTo: string | null, inviteCode?: string, options?: {
|
|
44
|
+
export declare function buildOidcLoginUrl(origin: string, { authorizationEndpoint, clientId, responseType, scope, extraParams, idpId, pkce, }: Partial<OidcLoginParams>, redirectTo: string | null, inviteCode?: string, options?: {
|
|
45
45
|
redirectUriOverride?: string;
|
|
46
46
|
sourceOverride?: 'portal' | 'mcp';
|
|
47
47
|
branchOverride?: string | undefined;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Context, Next } from 'hono';
|
|
2
|
-
export declare function catalogAuthMiddleware({ serverOutDir, protectReadMethods }: {
|
|
2
|
+
export declare function catalogAuthMiddleware({ serverOutDir, protectReadMethods, }: {
|
|
3
3
|
serverOutDir: string;
|
|
4
4
|
protectReadMethods?: boolean;
|
|
5
5
|
}): (ctx: Context, next: Next) => Promise<Response | void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{setCookie as R,deleteCookie as Y}from"hono/cookie";import{AuthProviderType as Q,DEFAULT_TEAM_CLAIM_NAME as x}from"@redocly/config";import{withPathPrefix as _,getPathPrefix as y}from"@redocly/theme/core/utils";import{compareURIs as ee}from"../../../utils/url/compare-uris.js";import{ensureArray as q}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as F,JWT_SECRET_KEY as v,ORG_SLUG as re,ORG_ID as oe}from"../../constants/common.js";import{AUTH_SEGMENT as ne,ServerRoutes as P}from"../../../constants/api.js";import{AuthCookieNames as L,DEFAULT_COOKIE_EXPIRATION as H}from"../../../constants/common.js";import{sanitizeRedirectPathname as B}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as T}from"../../telemetry/index.js";import{envConfig as j}from"../../config/env-config.js";import{fetchWithClient as te}from"../../utils/fetch-with-client.js";import{clearAuthCookies as K,clearPostLogoutCookie as $,hasPostLogoutCookie as se,setPostLogoutCookie as z}from"../../utils/cookie.js";import{getAuthProviderLoginParams as ie,isOidcProviderConfig as E,isSaml2ProviderConfig as ae,oidcExchangeCodeForToken as de,buildLoginUrl as ce,decodeSamlResponse as le,extractUserClaims as ue,parseSamlResponse as pe,parseOidcState as ge,verifySAMLResponse as fe,getUsernameFromPayload as me,buildOidcLogoutUrl as he,getOidcMetadata as G,getRedoclyTokenPayload as Ce,isRedoclySso as Ae,rewritePreviewAuthRedirectUri as Ie,parsePreviewBranch as J,buildOidcLoginUrl as we,createMcpSessionResource as D}from"../auth.js";import*as k from"../jwt/jwt.js";import{AlgorithmTypes as U}from"../jwt/types.js";import{handleErrorPageRender as Le}from"../utils.js";import{encodeBase64URL as Re}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as _e}from"./helpers/resolve-ui-locales-for-idp-login.js";async function je(s){if(j.isProductionEnv)return s.newResponse(null,404,{});const{password:e,...r}=await s.req.json(),a=await k.sign({...r,name:r.username||r.email||"Unknown"},v,U.HS256);return R(s,L.AUTHORIZATION,a,{path:y()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),$(s),s.newResponse(null,200,{})}function Ke(){return async s=>{const e=s.get("logger"),r=encodeURIComponent(s.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${P.LOGIN}/?error=${encodeURIComponent(r)}`;return s.newResponse(null,301,{Location:a})}}function Z(s){if(!s||!s.includes(P.MCP_CALLBACK))return null;try{const e=s.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 ze(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=ge(e.req.query("state")),m=o.idpId,t=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK),c=t?Z(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,i=a?.[m];if(!E(i))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await G(m,i);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,u=e.req.query("code"),h=e.req.query("error");if(h)return t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:`OIDC error: ${h}`,error_details:e.req.query("error_description")||null}]),Le(e,s,{slug:"/"},403,"403OIDC");if(!u){const A="Code is expected but not present";return r.error(`OIDC login error: ${A}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:A,error_details:null}]),new Response(`Forbidden: ${A}`,{status:403})}const w=typeof o.redirectUri=="string"?o.redirectUri:new URL(_(P.OIDC_CALLBACK),e.req.url).toString(),C=e.get("cookies")?.code_verifier,l=await de(p,u,w,i,{...i.tokenRequestCustomParams,...C?{code_verifier:C}:{}});if(l.error)return r.error(`Error from OIDC provider: "${l.error}"`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:`Token exchange error: ${l.error}`,error_details:l.error_description||null}]),e.text(`Forbidden: ${l.error_description||l.error}`,403);if(!l?.id_token){const A="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${A}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:A,error_details:null}]),new Response(`Forbidden: ${A}`,{status:403})}const{payload:f,header:M}=k.decode(l.id_token),n=M.alg===U.RS256;if(i.audience?.length&&![...q(f.aud||[]),...q(f[F]||[])].some(O=>i.audience?.includes(O))){const O="No valid audience found in id_token";return r.error(`OIDC login error: ${O}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:O,error_details:null}]),new Response(`Forbidden: ${O}`)}const g=n?l.id_token:await k.sign({...f,idpId:m},v,U.HS256);me(f)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const S=i?.tokenExpirationTime?Date.now()+i.tokenExpirationTime*1e3:f.exp*1e3||Date.now()+H*1e3;if(i.introspectEndpoint){const A=await fetch(i.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:l.access_token})});if(A.ok){const b=(await A.json()).ext?.federatedIdentity;b&&(R(e,L.FEDERATED_ACCESS_TOKEN,b.access_token||"",{path:y()||"/",httpOnly:!1,expires:new Date(S)}),R(e,L.FEDERATED_ID_TOKEN,b.id_token||"",{path:y()||"/",httpOnly:!1,expires:new Date(S)}))}else r.warn(`OIDC introspect error: ${A.statusText}`)}if(R(e,L.AUTHORIZATION,g,{path:y()||"/",httpOnly:!0,expires:new Date(S)}),g!==l.id_token&&R(e,L.IDP_ID_TOKEN,l.id_token||"",{path:y()||"/",httpOnly:!0,expires:new Date(S)}),R(e,L.IDP_ACCESS_TOKEN,l.access_token||"",{path:y()||"/",httpOnly:!0,expires:new Date(S)}),Y(e,"code_verifier",{path:y()||"/"}),$(e),t&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK)){const O=`${e.req.url.split("?")[0].replace(P.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:O})}const V=typeof o.redirectTo=="string"?o.redirectTo:void 0;let W=B(new URL(V||"/",e.req.url).pathname);const X=e.newResponse(null,302,{Location:W});return r.updateContext({email:f.email,subject:f.sub}),r.info("OIDC login successful"),X}catch(p){const u=p instanceof Error?p.message:String(p),h=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${u}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:u,error_details:h}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const I="Something went wrong";return r.error(`OIDC login error: ${I}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:I,error_details:null}]),e.text(I,500)}}function Ge(s){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,t=s.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return E(t)||(K(e),z(e)),r.info("Logout successful"),e.newResponse(null,200,{});let c;if(E(t)){const i=(await G(o,t)).end_session_endpoint;if(i){const d=new URL(e.req.url),I=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,u=`${I}://${p}`,h=J(u),w=h?Re(JSON.stringify({branch:J(u)})):void 0,C=h?`${Ie(u)}/${ne}/logout`:`${u}${_(P.POST_LOGOUT)}`;c=he(i,C,e.get("cookies")?.[L.IDP_ID_TOKEN]||e.get("cookies")?.[L.AUTHORIZATION]||"",w)}}return r.info("Logout successful"),K(e),z(e),e.newResponse(null,302,{Location:c||_("/")})}}function Je(s){return async e=>{const r=s.getConfig().access?.logoutReturnUrl,a=r||_("/");return e.newResponse(null,302,{Location:a})}}function Ze(s){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=j.BH_API_URL,m=(t,c,i)=>t&&c?`${t} ${c.charAt(0)}`:i;try{if(!o)throw new Error("BH_API_URL is not set");const t=s.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(_("/"));const c=await te(`${o}/user-invites/public/${a}`);if(!c.ok)return c.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(_("/"))):(r.error("Invite error",await c.text()),e.redirect(_("/")));const i=await c.json(),d=new URL(_("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",i.organization.name),d.searchParams.set("invitedBy",m(i.invitedBy.firstName,i.invitedBy.lastName,i.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 Ve(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=new URL(e.req.url),m=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",c=e.req.header("x-forwarded-host")||o.host,i=`${t}://${c}`;let d=o.searchParams.get("idpId");const I=o.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const u=o.searchParams.get("mcp_redirect_uri"),h=!!u;if(!a?.[d]){const g="Invalid idpId";if(r.error(`IdP login error: ${g}`),h){const N=Z(I||void 0);T.sendMcpAuthorizationFailedMessage([{...D(N),error:g,error_details:null}])}return e.text(`Forbidden: ${g}`,403)}const C=_e({localePrefixParam:o.searchParams.get("localePrefix"),l10n:s.getGlobalData()?.l10n}),l=d&&a?await ie(d,a[d]):void 0,f={};for(const g of Object.keys(l?.extraParams||{}))f[g]=o.searchParams.get(g)||l?.extraParams?.[g]||void 0;se(e)&&(f.prompt="login",f.post_logout="1");let M,n={};if(h&&u&&l&&l.type===Q.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${u}`);const g=we("",{...l,extraParams:f},I,m,{redirectUriOverride:u,sourceOverride:"mcp",branchOverride:void 0,uiLocales:C});M=g.loginUrl,n=g.cookies||{}}else if(l){const g=ce({...l,extraParams:f},i,I,m,C);M=g.loginUrl,n=g.cookies||{}}return Object.keys(n).forEach(g=>{R(e,g,n[g].value,n[g].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:M||new URL(e.req.url).pathname})}}function We(s){return async e=>{const r=e.get("logger"),a=await e.req.formData(),o=a.get("SAMLResponse"),m=a.get("RelayState");if(typeof o!="string"||typeof m!="string"){const n="SAMLResponse is required";return r.error(`SAML2 login error: ${n}`),e.text(`Bad request: ${n}`,400)}const t=le(o),{success:c,uid:i,nameFormat:d,attrs:I,issuerId:p,expiresAt:u}=pe(t),{idpId:h,redirectTo:w}=JSON.parse(m);if(!c){const n="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!u||Math.ceil(Date.now()/1e3)>=u){const n="SAML2 Token Expired";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const C=s.getConfig().ssoDirect?.[h];if(!C||!ae(C)){const n="Cannot find valid IdP";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!(C.issuerId&&p&&ee(C.issuerId,p))){const n="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!await fe(t,C.x509PublicCert)){const n="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const f=ue(i,d,I,C.teamsAttributeName??x);if(!f.sub){const n="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}if(!f.email){const n="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}const M=await k.sign({...f,idpId:h},v,U.HS256);return R(e,L.AUTHORIZATION,M,{path:y()||"/",httpOnly:!0,expires:new Date(u*1e3)}),$(e),r.updateContext({email:f.email,subject:f.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:w||"/"})}}function Xe(s){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=_(B(a.pathname)),m=s.getConfig().ssoDirect,t=Object.entries(m||{}).find(([,w])=>E(w)&&Ae(w));if(!(m&&t))return e.newResponse(null,302,{Location:o});const i=e.req.query("token"),d=i&&await Ce(i);if(!d)return e.newResponse(null,302,{Location:o});if(!q(d[F]||[]).some(w=>w===re||w===oe))return e.newResponse(null,302,{Location:o});const u=await k.sign({...d,idpId:t?.at(0)},v,U.HS256),h=Date.now()+H*1e3;return R(e,L.AUTHORIZATION,u,{path:y()||"/",httpOnly:!0,expires:new Date(h),sameSite:"None",secure:!0}),$(e),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{je as authorizeHandler,Ve as idpLoginHandler,Ze as inviteHandler,Ge as logoutHandler,ze as oidcCallbackHandler,Je as postLogoutHandler,Ke as redoclyLoginCallbackHandler,Xe as redoclyTokenLoginHandler,We as samlCallbackHandler};
|
|
1
|
+
import{setCookie as R,deleteCookie as Y}from"hono/cookie";import{AuthProviderType as Q,DEFAULT_TEAM_CLAIM_NAME as x}from"@redocly/config";import{withPathPrefix as _,getPathPrefix as y}from"@redocly/theme/core/utils";import{compareURIs as ee}from"../../../utils/url/compare-uris.js";import{ensureArray as q}from"../../../utils/array/ensure-array.js";import{ALTERNATIVE_AUD_CLAIM_NAME as F,JWT_SECRET_KEY as v,ORG_SLUG as re,ORG_ID as oe}from"../../constants/common.js";import{AUTH_SEGMENT as ne,ServerRoutes as P}from"../../../constants/api.js";import{AuthCookieNames as L,DEFAULT_COOKIE_EXPIRATION as H}from"../../../constants/common.js";import{sanitizeRedirectPathname as B}from"../../../utils/url/sanitize-redirect-pathname.js";import{telemetry as T}from"../../telemetry/index.js";import{envConfig as j}from"../../config/env-config.js";import{fetchWithClient as te}from"../../utils/fetch-with-client.js";import{clearAuthCookies as K,clearPostLogoutCookie as $,hasPostLogoutCookie as se,setPostLogoutCookie as z}from"../../utils/cookie.js";import{getAuthProviderLoginParams as ie,isOidcProviderConfig as E,isSaml2ProviderConfig as ae,oidcExchangeCodeForToken as de,buildLoginUrl as ce,decodeSamlResponse as le,extractUserClaims as ue,parseSamlResponse as pe,parseOidcState as ge,verifySAMLResponse as fe,getUsernameFromPayload as me,buildOidcLogoutUrl as he,getOidcMetadata as G,getRedoclyTokenPayload as Ce,isRedoclySso as Ae,rewritePreviewAuthRedirectUri as Ie,parsePreviewBranch as J,buildOidcLoginUrl as we,createMcpSessionResource as D}from"../auth.js";import*as k from"../jwt/jwt.js";import{AlgorithmTypes as U}from"../jwt/types.js";import{handleErrorPageRender as Le}from"../utils.js";import{encodeBase64URL as Re}from"../jwt/encode.js";import{resolveUiLocalesForIdpLogin as _e}from"./helpers/resolve-ui-locales-for-idp-login.js";async function je(s){if(j.isProductionEnv)return s.newResponse(null,404,{});const{password:e,...r}=await s.req.json(),a=await k.sign({...r,name:r.username||r.email||"Unknown"},v,U.HS256);return R(s,L.AUTHORIZATION,a,{path:y()||"/",httpOnly:!0,secure:!0,sameSite:"none"}),$(s),s.newResponse(null,200,{})}function Ke(){return async s=>{const e=s.get("logger"),r=encodeURIComponent(s.req.query("message")||"");e.error(`Login error: ${r}`);const a=`${P.LOGIN}/?error=${encodeURIComponent(r)}`;return s.newResponse(null,301,{Location:a})}}function Z(s){if(!s||!s.includes(P.MCP_CALLBACK))return null;try{const e=s.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 ze(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=ge(e.req.query("state")),m=o.idpId,t=o.source==="mcp"||o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK),c=t?Z(typeof o.redirectTo=="string"?o.redirectTo:void 0):null,i=a?.[m];if(!E(i))return r.error("OIDC login error: missing OIDC provider config"),e.text("Forbidden",403);const d=await G(m,i);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,u=e.req.query("code"),h=e.req.query("error");if(h)return t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:`OIDC error: ${h}`,error_details:e.req.query("error_description")||null}]),Le(e,s,{slug:"/"},403,"403OIDC");if(!u){const A="Code is expected but not present";return r.error(`OIDC login error: ${A}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:A,error_details:null}]),new Response(`Forbidden: ${A}`,{status:403})}const w=typeof o.redirectUri=="string"?o.redirectUri:new URL(_(P.OIDC_CALLBACK),e.req.url).toString(),C=e.get("cookies")?.code_verifier,l=await de(p,u,w,i,{...i.tokenRequestCustomParams,...C?{code_verifier:C}:{}});if(l.error)return r.error(`Error from OIDC provider: "${l.error}"`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:`Token exchange error: ${l.error}`,error_details:l.error_description||null}]),e.text(`Forbidden: ${l.error_description||l.error}`,403);if(!l?.id_token){const A="No id_token, please, add openid to scopes";return r.error(`OIDC login error: ${A}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:A,error_details:null}]),new Response(`Forbidden: ${A}`,{status:403})}const{payload:f,header:M}=k.decode(l.id_token),n=M.alg===U.RS256;if(i.audience?.length&&![...q(f.aud||[]),...q(f[F]||[])].some(O=>i.audience?.includes(O))){const O="No valid audience found in id_token";return r.error(`OIDC login error: ${O}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:O,error_details:null}]),new Response(`Forbidden: ${O}`)}const g=n?l.id_token:await k.sign({...f,idpId:m},v,U.HS256);me(f)||r.warn("To display your username, the required 'email' or 'full_profile' scope must be added to the identity provider configuration");const S=i?.tokenExpirationTime?Date.now()+i.tokenExpirationTime*1e3:f.exp*1e3||Date.now()+H*1e3;if(i.introspectEndpoint){const A=await fetch(i.introspectEndpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({access_token:l.access_token})});if(A.ok){const b=(await A.json()).ext?.federatedIdentity;b&&(R(e,L.FEDERATED_ACCESS_TOKEN,b.access_token||"",{path:y()||"/",httpOnly:!1,expires:new Date(S)}),R(e,L.FEDERATED_ID_TOKEN,b.id_token||"",{path:y()||"/",httpOnly:!1,expires:new Date(S)}))}else r.warn(`OIDC introspect error: ${A.statusText}`)}if(R(e,L.AUTHORIZATION,g,{path:y()||"/",httpOnly:!0,expires:new Date(S)}),g!==l.id_token&&R(e,L.IDP_ID_TOKEN,l.id_token||"",{path:y()||"/",httpOnly:!0,expires:new Date(S)}),R(e,L.IDP_ACCESS_TOKEN,l.access_token||"",{path:y()||"/",httpOnly:!0,expires:new Date(S)}),Y(e,"code_verifier",{path:y()||"/"}),$(e),t&&o.redirectTo&&typeof o.redirectTo=="string"&&o.redirectTo.includes(P.MCP_CALLBACK)){const O=`${e.req.url.split("?")[0].replace(P.OIDC_CALLBACK,"")}${o.redirectTo}`;return e.newResponse(null,302,{Location:O})}const V=typeof o.redirectTo=="string"?o.redirectTo:void 0;let W=B(new URL(V||"/",e.req.url).pathname);const X=e.newResponse(null,302,{Location:W});return r.updateContext({email:f.email,subject:f.sub}),r.info("OIDC login successful"),X}catch(p){const u=p instanceof Error?p.message:String(p),h=p instanceof Error?p.stack:String(p);if(r.error(`OIDC login error: ${u}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:u,error_details:h}]),p.error==="access_denied")return r.info("Access denied"),e.text("Forbidden",403)}const I="Something went wrong";return r.error(`OIDC login error: ${I}`),t&&T.sendMcpAuthorizationFailedMessage([{...D(c),error:I,error_details:null}]),e.text(I,500)}}function Ge(s){return async e=>{const r=e.get("logger"),o=e.get("auth").claims?.idpId,t=s.getConfig().ssoDirect?.[o];if(e.req.method==="POST")return E(t)||(K(e),z(e)),r.info("Logout successful"),e.newResponse(null,200,{});let c;if(E(t)){const i=(await G(o,t)).end_session_endpoint;if(i){const d=new URL(e.req.url),I=e.req.header("x-forwarded-proto")||d.protocol.slice(0,-1)||"https",p=e.req.header("x-forwarded-host")||d.host,u=`${I}://${p}`,h=J(u),w=h?Re(JSON.stringify({branch:J(u)})):void 0,C=h?`${Ie(u)}/${ne}/logout`:`${u}${_(P.POST_LOGOUT)}`;c=he(i,C,e.get("cookies")?.[L.IDP_ID_TOKEN]||e.get("cookies")?.[L.AUTHORIZATION]||"",w)}}return r.info("Logout successful"),K(e),z(e),e.newResponse(null,302,{Location:c||_("/")})}}function Je(s){return async e=>{const r=s.getConfig().access?.logoutReturnUrl,a=r||_("/");return e.newResponse(null,302,{Location:a})}}function Ze(s){return async e=>{const r=e.get("logger"),a=e.req.param("code"),o=j.BH_API_URL,m=(t,c,i)=>t&&c?`${t} ${c.charAt(0)}`:i;try{if(!o)throw new Error("BH_API_URL is not set");const t=s.getConfig().ssoDirect;if(!t||!Object.keys(t).length)return r.warn("Invite no sso configured to handle"),e.redirect(_("/"));const c=await te(`${o}/public-user-invites/${a}`);if(!c.ok)return c.status===404?(r.warn(`Invite ${a} not found redirect to homepage`),e.redirect(_("/"))):(r.error("Invite error",await c.text()),e.redirect(_("/")));const i=await c.json(),d=new URL(_("/invite"),e.req.url);return d.searchParams.set("code",a),d.searchParams.set("org",i.organization.name),d.searchParams.set("invitedBy",m(i.invitedBy.firstName,i.invitedBy.lastName,i.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 Ve(s){return async e=>{const r=e.get("logger"),a=s.getConfig().ssoDirect,o=new URL(e.req.url),m=e.req.query("inviteCode"),t=e.req.header("x-forwarded-proto")||o.protocol.slice(0,-1)||"https",c=e.req.header("x-forwarded-host")||o.host,i=`${t}://${c}`;let d=o.searchParams.get("idpId");const I=o.searchParams.get("redirectTo"),p=Object.keys(a||{})[0];d=d||p;const u=o.searchParams.get("mcp_redirect_uri"),h=!!u;if(!a?.[d]){const g="Invalid idpId";if(r.error(`IdP login error: ${g}`),h){const N=Z(I||void 0);T.sendMcpAuthorizationFailedMessage([{...D(N),error:g,error_details:null}])}return e.text(`Forbidden: ${g}`,403)}const C=_e({localePrefixParam:o.searchParams.get("localePrefix"),l10n:s.getGlobalData()?.l10n}),l=d&&a?await ie(d,a[d]):void 0,f={};for(const g of Object.keys(l?.extraParams||{}))f[g]=o.searchParams.get(g)||l?.extraParams?.[g]||void 0;se(e)&&(f.prompt="login",f.post_logout="1");let M,n={};if(h&&u&&l&&l.type===Q.OIDC){r.info(`Building MCP OAuth login URL with redirect_uri: ${u}`);const g=we("",{...l,extraParams:f},I,m,{redirectUriOverride:u,sourceOverride:"mcp",branchOverride:void 0,uiLocales:C});M=g.loginUrl,n=g.cookies||{}}else if(l){const g=ce({...l,extraParams:f},i,I,m,C);M=g.loginUrl,n=g.cookies||{}}return Object.keys(n).forEach(g=>{R(e,g,n[g].value,n[g].options)}),r.info(`IdP login initiated for ID '${d}'`),e.newResponse(null,302,{Location:M||new URL(e.req.url).pathname})}}function We(s){return async e=>{const r=e.get("logger"),a=await e.req.formData(),o=a.get("SAMLResponse"),m=a.get("RelayState");if(typeof o!="string"||typeof m!="string"){const n="SAMLResponse is required";return r.error(`SAML2 login error: ${n}`),e.text(`Bad request: ${n}`,400)}const t=le(o),{success:c,uid:i,nameFormat:d,attrs:I,issuerId:p,expiresAt:u}=pe(t),{idpId:h,redirectTo:w}=JSON.parse(m);if(!c){const n="SAML2 assertion is not successful";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!u||Math.ceil(Date.now()/1e3)>=u){const n="SAML2 Token Expired";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const C=s.getConfig().ssoDirect?.[h];if(!C||!ae(C)){const n="Cannot find valid IdP";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!(C.issuerId&&p&&ee(C.issuerId,p))){const n="IssuerID is misconfigured or untrusted assertions issuer received";return r.error(`SAML2 login error: ${n}`),e.text(`Permission denied: ${n}`,401)}if(!await fe(t,C.x509PublicCert)){const n="SAMLResponse signature invalid";return r.error(`SAML2 login error: ${n}`),e.text(n,401)}const f=ue(i,d,I,C.teamsAttributeName??x);if(!f.sub){const n="The provider did not return a valid user identity.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}if(!f.email){const n="The provider did not return a valid user email.";return r.error(`SAML2 login error: ${n}`),e.text(n,400)}const M=await k.sign({...f,idpId:h},v,U.HS256);return R(e,L.AUTHORIZATION,M,{path:y()||"/",httpOnly:!0,expires:new Date(u*1e3)}),$(e),r.updateContext({email:f.email,subject:f.sub}),r.info("SAML2 login successful"),e.newResponse(null,302,{Location:w||"/"})}}function Xe(s){return async e=>{const r=e.get("logger"),a=new URL(e.req.query("redirectTo")||"/",e.req.url),o=_(B(a.pathname)),m=s.getConfig().ssoDirect,t=Object.entries(m||{}).find(([,w])=>E(w)&&Ae(w));if(!(m&&t))return e.newResponse(null,302,{Location:o});const i=e.req.query("token"),d=i&&await Ce(i);if(!d)return e.newResponse(null,302,{Location:o});if(!q(d[F]||[]).some(w=>w===re||w===oe))return e.newResponse(null,302,{Location:o});const u=await k.sign({...d,idpId:t?.at(0)},v,U.HS256),h=Date.now()+H*1e3;return R(e,L.AUTHORIZATION,u,{path:y()||"/",httpOnly:!0,expires:new Date(h),sameSite:"None",secure:!0}),$(e),r.info("Token login successful"),e.newResponse(null,302,{Location:o})}}export{je as authorizeHandler,Ve as idpLoginHandler,Ze as inviteHandler,Ge as logoutHandler,ze as oidcCallbackHandler,Je as postLogoutHandler,Ke as redoclyLoginCallbackHandler,Xe as redoclyTokenLoginHandler,We as samlCallbackHandler};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Context } from 'hono';
|
|
2
2
|
import type { Store } from '../../../../store';
|
|
3
|
-
export declare function hasAccessToEntity({ ctx, store, accessLevel, entityType, entityKey }: {
|
|
3
|
+
export declare function hasAccessToEntity({ ctx, store, accessLevel, entityType, entityKey, }: {
|
|
4
4
|
ctx: Context;
|
|
5
5
|
store: Store;
|
|
6
6
|
accessLevel: 'READ' | 'WRITE';
|
|
@@ -7,6 +7,6 @@ type UpsertPagesStatsParams = {
|
|
|
7
7
|
addedEntities?: EntityReadModelSchema[];
|
|
8
8
|
removedEntities?: EntityReadModelSchema[];
|
|
9
9
|
};
|
|
10
|
-
export declare function upsertPagesStats({ ctx, catalogEntitiesService, addedEntities, removedEntities }: UpsertPagesStatsParams): Promise<void>;
|
|
10
|
+
export declare function upsertPagesStats({ ctx, catalogEntitiesService, addedEntities, removedEntities, }: UpsertPagesStatsParams): Promise<void>;
|
|
11
11
|
export {};
|
|
12
12
|
//# sourceMappingURL=upsert-pages-stats.d.ts.map
|
|
@@ -16,7 +16,7 @@ type FeedbackData = {
|
|
|
16
16
|
email?: string;
|
|
17
17
|
};
|
|
18
18
|
export declare function normalizeFeedbackMetadata(metadata?: FeedbackData['metadata']): Record<string, any> | undefined;
|
|
19
|
-
export declare function normalizeFeedbackData({ component, path, location, lang, agent, targetFeature, score, max, reasons, comment, metadata, email }: FeedbackData): {
|
|
19
|
+
export declare function normalizeFeedbackData({ component, path, location, lang, agent, targetFeature, score, max, reasons, comment, metadata, email, }: FeedbackData): {
|
|
20
20
|
feedbackComponent: string;
|
|
21
21
|
path: string | undefined;
|
|
22
22
|
location: string | undefined;
|
|
@@ -22,7 +22,7 @@ import type { StatusCode } from 'hono/utils/http-status';
|
|
|
22
22
|
* processRedirects({ redirect: { to: 'https://example.com', type: 302 } });
|
|
23
23
|
* // Returns: { location: 'https://example.com', type: 302 }
|
|
24
24
|
*/
|
|
25
|
-
export declare function processRedirects({ redirect, reqUrlSearch }: {
|
|
25
|
+
export declare function processRedirects({ redirect, reqUrlSearch, }: {
|
|
26
26
|
redirect: WithRequired<RedirectConfig, 'to'>;
|
|
27
27
|
reqUrlSearch?: string;
|
|
28
28
|
}): {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Handler } from 'hono';
|
|
2
|
+
import type { Store } from '../../../store.js';
|
|
2
3
|
export type McpContextPayload = {
|
|
3
4
|
isMcpFlow: boolean;
|
|
4
5
|
originalRedirectUri: string | null;
|
|
@@ -12,14 +13,14 @@ export type McpContextPayload = {
|
|
|
12
13
|
export declare function verifyPkce(codeChallenge: string, codeChallengeMethod: string | undefined, codeVerifier: string): boolean;
|
|
13
14
|
export declare function createMcpContextToken(context: McpContextPayload): Promise<string>;
|
|
14
15
|
export declare function verifyAndParseMcpContextToken(token: string): Promise<McpContextPayload>;
|
|
15
|
-
export declare function mcpOAuthProtectedResourceHandler(): Handler;
|
|
16
|
-
export declare function mcpOAuthAuthorizationServerHandler(): Handler;
|
|
16
|
+
export declare function mcpOAuthProtectedResourceHandler(store: Store): Handler;
|
|
17
|
+
export declare function mcpOAuthAuthorizationServerHandler(store: Store): Handler;
|
|
17
18
|
/**
|
|
18
19
|
* This code is not used in the MCP server, but it is required to satisfy the OAuth 2.0 Dynamic Client Registration Protocol.
|
|
19
20
|
* Also it is simulating the client registration process.
|
|
20
21
|
*/
|
|
21
|
-
export declare function mcpDynamicClientRegistrationHandler(): Handler;
|
|
22
|
-
export declare function mcpAuthorizationHandler(): Handler;
|
|
22
|
+
export declare function mcpDynamicClientRegistrationHandler(store: Store): Handler;
|
|
23
|
+
export declare function mcpAuthorizationHandler(store: Store): Handler;
|
|
23
24
|
export declare function mcpTokenPortalHandler(): Handler;
|
|
24
25
|
export declare function mcpCallbackHandler(): Handler;
|
|
25
26
|
//# sourceMappingURL=mcp-oauth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getCookie as
|
|
1
|
+
import{getCookie as S}from"hono/cookie";import{createHash as D,timingSafeEqual as L}from"node:crypto";import{ulid as H}from"ulid";import{isMcpContentProtected as C}from"../../../plugins/mcp/auth/auth-handlers.js";import{isRedoclySso as q,isOidcProviderConfig as z}from"../../auth.js";import{AUTH_URL as M,JWT_SECRET_KEY as A}from"../../../constants/common.js";import{ServerRoutes as u}from"../../../../constants/api.js";import{AuthCookieNames as k}from"../../../../constants/common.js";import{withPathPrefix as _}from"@redocly/theme/core/utils";import{telemetry as m}from"../../../telemetry/index.js";import{envConfig as I}from"../../../config/env-config.js";import{createMcpAuthorizationCode as $,verifyMcpAuthorizationCode as N,createMcpSessionResource as f}from"../../auth.js";import*as h from"../../jwt/jwt.js";import{AlgorithmTypes as w}from"../../jwt/types.js";import{getRequestOrigin as E}from"../../utils/get-request-origin.js";import{fetchClientMetadataDocument as b,isClientMetadataDocumentUrl as P,isRedirectUriRegistered as j}from"./mcp-client-metadata.js";const o=(r,e,n=200,a)=>r.json(e,n,{"Content-Type":"application/json",...a??{}}),U=new Set(["S256"]),B="https://claude.ai/oauth/claude-code-client-metadata";function F(r,e,n){if(!U.has(e||""))return!1;const a=D("sha256").update(n).digest("base64url"),t=Buffer.from(a),s=Buffer.from(r);return t.length!==s.length?!1:L(t,s)}async function K(r){const e=Math.floor(Date.now()/1e3);return h.sign({type:"mcp_context",...r,iat:e,exp:e+600},A,w.HS256)}async function G(r){await h.verify(r,A,w.HS256);const{payload:e}=h.decode(r);if(e.type!=="mcp_context")throw new Error("Invalid context token type");return e}function se(r){return async e=>{if(!C(r))return o(e,{error:"not_found"},404);if(e.req.method!=="GET")return o(e,{error:"Method not allowed"},405,{Allow:"GET"});const n=E(e);return o(e,{resource:`${n}${_("/mcp")}`,authorization_servers:[n,M].filter(Boolean),bearer_methods_supported:["header"],resource_documentation:`${n}${u.MCP_OAUTH_AUTHORIZATION_SERVER}`,scopes_supported:["openid","profile","email","offline_access"],bearer_token_types_supported:["Bearer"]})}}function ce(r){return async e=>{if(!C(r))return o(e,{error:"not_found"},404);const n=E(e);return o(e,{issuer:M||"",authorization_endpoint:`${n}${_(u.MCP_AUTHORIZATION)}`,token_endpoint:`${n}${_(u.MCP_TOKEN_PORTAL)}`,jwks_uri:`${M||""}/.well-known/jwks.json`,scopes_supported:["openid","profile","email","offline_access"],registration_endpoint:`${n}${_(u.MCP_DYNAMIC_CLIENT_REGISTRATION)}`,response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token","client_credentials"],subject_types_supported:["public"],id_token_signing_alg_values_supported:["RS256"],code_challenge_methods_supported:["S256"],token_endpoint_auth_methods_supported:["none"],client_id_metadata_document_supported:!0})}}function de(r){return async e=>{if(!C(r))return o(e,{error:"not_found"},404);if(e.req.method!=="POST")return o(e,{error:"Method not allowed"},405);try{return o(e,{client_id:I.OAUTH_CLIENT_ID||"",client_name:"MCP Client",redirect_uris:[],grant_types:["authorization_code","refresh_token"],response_types:["code"],scope:"openid offline email",subject_type:"public",token_endpoint_auth_method:"none",created_at:new Date().toISOString(),updated_at:new Date().toISOString()},201)}catch(n){return o(e,{error:"invalid_request",error_description:n?.message||"Unable to register client"},500)}}}function le(r){return async e=>{if(!C(r))return o(e,{error:"not_found"},404);const n=new URL(e.req.url),{searchParams:a}=n,t=a.get("redirect_uri"),s=a.get("client_id"),i=a.get("code_challenge"),d=a.get("code_challenge_method"),l=H();if(i&&!U.has(d||""))return o(e,{error:"invalid_request",error_description:`Unsupported code_challenge_method. Supported: ${[...U].join(", ")}`},400);if(P(s)&&!i)return o(e,{error:"invalid_request",error_description:"code_challenge is required for client_id_metadata_document clients"},400);if(P(s)&&t)try{const c=await b(s),p=s===B;if(!j(t,c.redirect_uris,{ignorePort:p}))return o(e,{error:"invalid_request",error_description:"redirect_uri is not registered for this client"},400)}catch(c){const p=c instanceof Error?c.message:String(c);return o(e,{error:"invalid_client",error_description:`Unable to resolve client metadata document: ${p}`},400)}m.sendMcpAuthorizationStartedMessage([{...f(l),redirect_uri:t||null}]);const v=E(e),T={isMcpFlow:!0,originalRedirectUri:t,mcpClientId:s,mcpState:a.get("state"),mcpSessionId:l,mcpCodeChallenge:i,mcpCodeChallengeMethod:i?d:null,timestamp:Date.now()};try{const c=await K(T),p=new URL(_(u.IDP_LOGIN),v);p.searchParams.set("redirectTo",`${u.MCP_CALLBACK}/${c}`);const g=r.getConfig().ssoDirect||{},R=Object.entries(g).find(([,O])=>z(O)&&q(O))?.[0]??Object.keys(g)[0];return R?(p.searchParams.set("idpId",R),e.redirect(p.toString())):o(e,{error:"not_found"},404)}catch(c){const p=c instanceof Error?c.message:String(c),g=c instanceof Error?c.stack:String(c);m.sendMcpAuthorizationFailedMessage([{...f(l),error:p,error_details:g}]);const y=new URL(_(`${M}/oauth2/auth`));return y.search=a.toString(),e.redirect(y.toString())}}}function pe(){return async r=>{if(r.req.method!=="POST")return o(r,{error:"Method not allowed"},405);try{const e=await r.req.formData(),n=e.get("grant_type"),a=e.get("code"),t=e.get("redirect_uri")||void 0,s=e.get("code_verifier")||void 0;if(n!=="authorization_code"||!a)return o(r,{error:"invalid_request",error_description:"Invalid grant type or missing authorization code"},400);try{const i=await N(a);if(t&&t!==i.redirect_uri)return o(r,{error:"invalid_grant",error_description:"redirect_uri mismatch"},400);if(i.code_challenge){if(!s)return o(r,{error:"invalid_grant",error_description:"code_verifier required"},400);if(!F(i.code_challenge,i.code_challenge_method,s))return o(r,{error:"invalid_grant",error_description:"code_verifier mismatch"},400)}if(I.OAUTH_CLIENT_ID&&i.client_id&&!P(i.client_id)&&i.client_id!==I.OAUTH_CLIENT_ID)return o(r,{error:"invalid_client",error_description:"Client mismatch"},400);const d=i.id_token;if(typeof d!="string"||d.length===0)return o(r,{error:"invalid_grant",error_description:"Missing id_token in authorization code"},400);let l=d;if(i.idp_access_token){const{payload:T,header:{kid:c}}=h.decode(d);l=await h.sign({...T,idp_access_token:i.idp_access_token},A,w.HS256,c)}return o(r,{access_token:l,token_type:"Bearer",expires_in:3600,scope:"openid profile email",id_token:d},200,{"Cache-Control":"no-store",Pragma:"no-cache"})}catch{return o(r,{error:"invalid_grant",error_description:"Invalid authorization code"},400)}}catch(e){const n=e instanceof Error?e.message:String(e);return o(r,{error:"server_error",error_description:"Failed to process token request",error_details:n},500)}}}function ue(){return async r=>{const e=new URL(r.req.url);let n=e.searchParams.get("context");if(!n&&e.pathname.startsWith(_(`${u.MCP_CALLBACK}/`))){const t=e.pathname.split("/");n=t[t.length-1]}if(!n)return m.sendMcpAuthorizationFailedMessage([{...f(null),error:"Missing context parameter",error_details:null}]),r.text("Missing context parameter",400);let a=null;try{const t=await G(n);if(a=t.mcpSessionId||null,!t.isMcpFlow||!t.originalRedirectUri)throw new Error("Invalid MCP context");const s=S(r,k.IDP_ID_TOKEN)||S(r,k.AUTHORIZATION),i=S(r,k.IDP_ACCESS_TOKEN);if(!s)return m.sendMcpAuthorizationFailedMessage([{...f(a),error:"Authentication required",error_details:null}]),r.text("Authentication required",401);const d=await $({idToken:s,idpAccessToken:i||void 0,clientId:t.mcpClientId||"",redirectUri:t.originalRedirectUri,codeChallenge:t.mcpCodeChallenge||void 0,codeChallengeMethod:t.mcpCodeChallengeMethod||void 0,ttlSec:600}),l=new URL(t.originalRedirectUri);return l.searchParams.set("code",d),t.mcpState&&l.searchParams.set("state",t.mcpState),m.sendMcpAuthorizationCompletedMessage([{...f(a),redirect_uri:t.originalRedirectUri||null}]),r.redirect(l.toString())}catch(t){const s=t instanceof Error?t.message:String(t),i=t instanceof Error?t.stack:String(t);return m.sendMcpAuthorizationFailedMessage([{...f(a),error:s,error_details:i}]),r.text(`Invalid MCP callback: ${s}`,400)}}}export{K as createMcpContextToken,le as mcpAuthorizationHandler,ue as mcpCallbackHandler,de as mcpDynamicClientRegistrationHandler,ce as mcpOAuthAuthorizationServerHandler,se as mcpOAuthProtectedResourceHandler,pe as mcpTokenPortalHandler,G as verifyAndParseMcpContextToken,F as verifyPkce};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{corsMiddleware as p}from"../../middleware/corsMiddleware.js";import{ServerRoutes as
|
|
1
|
+
import{corsMiddleware as p}from"../../middleware/corsMiddleware.js";import{ServerRoutes as i}from"../../../../constants/api.js";import{EntitlementsProvider as C}from"../../../entitlements/entitlements-provider.js";import{withPathPrefix as n}from"@redocly/theme/core/utils";import{AGENT_CARD_SLUG as l,A2A_SLUG as m,MCP_SERVER_CARD_SLUG as A}from"../../../../constants/common.js";import{mcpOAuthProtectedResourceHandler as d,mcpOAuthAuthorizationServerHandler as r,mcpDynamicClientRegistrationHandler as _,mcpAuthorizationHandler as s,mcpTokenPortalHandler as R,mcpCallbackHandler as o}from"./mcp-oauth.js";import{mcpServerCardHandler as E}from"./mcp-server-card.js";import{agentCardHandler as P}from"./agent-card.js";import{a2aHandler as T}from"./a2a.js";function N(e,t){const a=t.getConfig().mcp,c=C.instance().canAccessFeature("mcp");!a?.hide&&!a?.docs?.hide&&c&&(e.get(n(A),E(t)),e.get(n(l),P(t)),e.use(n(m),p({allowMethods:["POST"],exposeHeaders:["Link"]})),e.post(n(m),T(t)),e.get(`${i.MCP_OAUTH_PROTECTED_RESOURCE}${n("/mcp")}`,d(t)),e.get(i.MCP_OAUTH_AUTHORIZATION_SERVER,r(t)),e.post(n(i.MCP_DYNAMIC_CLIENT_REGISTRATION),_(t)),e.get(n(i.MCP_AUTHORIZATION),s(t)),e.post(n(i.MCP_TOKEN_PORTAL),R()),e.get(n(i.MCP_CALLBACK),o()),e.get(n(`${i.MCP_CALLBACK}/*`),o()))}export{N as installMcpRoutes};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SeoConfig } from '@redocly/config';
|
|
2
2
|
import type { Skill } from '../../../../types/plugins/skills.js';
|
|
3
3
|
import type { AgentCard } from '../types.js';
|
|
4
|
-
export declare function buildAgentCard({ seo, baseUrl, skills, mcpAuthRequired }: {
|
|
4
|
+
export declare function buildAgentCard({ seo, baseUrl, skills, mcpAuthRequired, }: {
|
|
5
5
|
seo: SeoConfig | undefined;
|
|
6
6
|
baseUrl: string;
|
|
7
7
|
skills: Skill[];
|
|
@@ -15,7 +15,7 @@ export type ListResponseResult<T extends {
|
|
|
15
15
|
};
|
|
16
16
|
export declare function prepareListResponse<T extends {
|
|
17
17
|
id: string;
|
|
18
|
-
}>({ data, params, totalCount, nameTransformationsFromDatabase, hasMore }: {
|
|
18
|
+
}>({ data, params, totalCount, nameTransformationsFromDatabase, hasMore, }: {
|
|
19
19
|
data: T[];
|
|
20
20
|
params: PaginationParams;
|
|
21
21
|
totalCount?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAllowedEnvs as r}from"../utils/envs/get-api-route-allowed-env-variables.js";import{WorkerPool as o}from"./worker-pool.js";const p="executeApiRoute",e=3,i=new o({workerScript:"./api-routes-worker",minWorkers:1,maxWorkers:e,workerType:"process",forkOpts:{stdio:"inherit"},resolveForkEnv:r,lazy:!0});export{p as API_ROUTES_WORKER_KEY,i as apiRoutesWorkers};
|
|
1
|
+
import{getAllowedEnvs as r}from"../utils/envs/get-api-route-allowed-env-variables.js";import{WorkerPool as o}from"./worker-pool.js";const p="executeApiRoute",e=3,i=new o({workerScript:"./api-routes-worker",minWorkers:1,maxWorkers:e,workerType:"process",forkOpts:{stdio:"inherit"},resolveForkEnv:r,lazy:!0,sandbox:!0});export{p as API_ROUTES_WORKER_KEY,i as apiRoutesWorkers};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getAllowedEnvs as o}from"../utils/envs/get-api-route-allowed-env-variables.js";import{WorkerPool as r}from"./worker-pool.js";const p="executeMcpTool",c="isMcpToolAvailable",e=5,l=new r({workerScript:"./mcp-tool-worker",minWorkers:1,maxWorkers:e,workerType:"process",forkOpts:{stdio:"inherit"},resolveForkEnv:o,lazy:!0});export{c as MCP_TOOL_IS_AVAILABLE_KEY,p as MCP_TOOL_WORKER_KEY,l as mcpToolWorkers};
|
|
1
|
+
import{getAllowedEnvs as o}from"../utils/envs/get-api-route-allowed-env-variables.js";import{WorkerPool as r}from"./worker-pool.js";const p="executeMcpTool",c="isMcpToolAvailable",e=5,l=new r({workerScript:"./mcp-tool-worker",minWorkers:1,maxWorkers:e,workerType:"process",forkOpts:{stdio:"inherit"},resolveForkEnv:o,lazy:!0,sandbox:!0});export{c as MCP_TOOL_IS_AVAILABLE_KEY,p as MCP_TOOL_WORKER_KEY,l as mcpToolWorkers};
|
|
@@ -3,6 +3,7 @@ import type { WorkerTypeMapping, WorkerParams, WorkerResponse } from './types.js
|
|
|
3
3
|
export type WorkerPoolConfig = {
|
|
4
4
|
workerScript: string;
|
|
5
5
|
lazy: boolean;
|
|
6
|
+
sandbox?: boolean;
|
|
6
7
|
resolveForkEnv?: () => Record<string, string | undefined>;
|
|
7
8
|
} & WorkerPoolOptions;
|
|
8
9
|
type RegisteredWorkers = keyof WorkerTypeMapping;
|