lib/local-preview-servers.ts
Rama main · réplica de lectura del repositorio original.
import { deflateRawSync, inflateRawSync } from "node:zlib";
import { withHostedEndpoint } from "@/lib/diagnostics";
import { type GenerationPipelineInput, type GenerationPipelineResult, runGenerationPipeline } from "@/lib/generation-pipeline";
import { findLocalGeneratedServer, localDemoUserId, saveLocalGeneratedServer } from "@/lib/local-demo";
import { buildMcpEndpoint } from "@/lib/urls";
import { assertPublicWebsiteUrl } from "@/lib/runtime/playwright-website";
import type { McpServer } from "@/lib/types";
import { inspectWebsiteForMcp } from "@/lib/website-inspector";
const WEBSITE_PREFIX = "website-preview-";
const OPENAPI_PREFIX = "openapi-preview-";
const MAX_SELF_DESCRIBING_ID_LENGTH = 3800;
function encodePayload(prefix: string, payload: unknown) {
const compressed = deflateRawSync(Buffer.from(JSON.stringify(payload), "utf8"));
return `${prefix}${compressed.toString("base64url")}`;
}
function decodePayload<T>(prefix: string, id: string): T | null {
if (!id.startsWith(prefix)) return null;
try {
const raw = Buffer.from(id.slice(prefix.length), "base64url");
return JSON.parse(inflateRawSync(raw).toString("utf8")) as T;
} catch {
return null;
}
}
function safePreviewId(prefix: string, payload: unknown) {
const id = encodePayload(prefix, payload);
return id.length <= MAX_SELF_DESCRIBING_ID_LENGTH ? id : null;
}
export function websitePreviewServerId(inputUrl: string) {
const url = assertPublicWebsiteUrl(inputUrl);
return safePreviewId(WEBSITE_PREFIX, { url: url.toString() });
}
export function openApiPreviewServerId(input: GenerationPipelineInput) {
return safePreviewId(OPENAPI_PREFIX, {
sourceType: input.sourceType,
sourceUrl: input.sourceUrl,
rawJson: input.rawJson,
selectedGroup: input.selectedGroup,
endpointLimit: input.endpointLimit,
generationMode: input.generationMode,
clientPreset: input.clientPreset,
filters: input.filters,
runtimePolicy: input.runtimePolicy,
});
}
export async function buildLocalWebsitePreviewServer(inputUrl: string, requestUrl?: string | URL) {
const inspected = await inspectWebsiteForMcp(inputUrl);
const id = websitePreviewServerId(inspected.sourceUrl) ?? "local-website-preview";
const hostedEndpoint = buildMcpEndpoint(id, requestUrl);
const diagnostics = withHostedEndpoint(inspected.diagnostics, hostedEndpoint);
const server: McpServer = {
id,
user_id: localDemoUserId,
name: inspected.generated.name,
description: inspected.generated.description,
source_url: inspected.sourceUrl,
source_type: "website",
category: "Website",
generated_code: inspected.generated.generated_code,
tools_json: inspected.generated.tools,
endpoint_map: inspected.endpointMap,
diagnostics,
status: "live",
validation_status: "passed",
generation_status: "completed",
hosted_endpoint: hostedEndpoint,
is_public: true,
call_count: 0,
generation_version: 1,
protocol_version: "2024-11-05",
created_at: new Date().toISOString(),
};
saveLocalGeneratedServer(server);
return { server, generated: inspected.generated, diagnostics };
}
export async function loadLocalWebsitePreviewServer(serverId: string, requestUrl?: string | URL) {
const cached = findLocalGeneratedServer(serverId);
if (cached) return cached;
const payload = decodePayload<{ url?: string }>(WEBSITE_PREFIX, serverId);
if (!payload?.url) return null;
return (await buildLocalWebsitePreviewServer(payload.url, requestUrl)).server;
}
export function buildLocalOpenApiPreviewServer(
input: GenerationPipelineInput,
pipeline: GenerationPipelineResult,
requestUrl?: string | URL,
explicitId?: string | null
) {
const id = explicitId ?? openApiPreviewServerId(input) ?? `local-generated-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
const hostedEndpoint = buildMcpEndpoint(id, requestUrl);
const diagnostics = withHostedEndpoint(pipeline.diagnostics, hostedEndpoint);
const server = saveLocalGeneratedServer({
id,
user_id: localDemoUserId,
name: pipeline.generated.name,
description: pipeline.generated.description,
source_url: pipeline.sourceUrl,
source_type: input.sourceType,
category: input.generationMode === "code" ? "Code Mode" : "OpenAPI",
generated_code: pipeline.generated.generated_code,
tools_json: pipeline.generated.tools,
endpoint_map: pipeline.endpointMap,
runtime_policy: input.runtimePolicy ?? null,
diagnostics,
status: "live",
validation_status: pipeline.validationStatus,
generation_status: pipeline.generationStatus,
is_public: input.runtimePolicy ? false : true,
hosted_endpoint: hostedEndpoint,
call_count: 0,
generation_version: 1,
protocol_version: "2024-11-05",
created_at: new Date().toISOString(),
} as McpServer);
return { server, generated: pipeline.generated, diagnostics };
}
export async function loadLocalOpenApiPreviewServer(serverId: string, requestUrl?: string | URL) {
const cached = findLocalGeneratedServer(serverId);
if (cached) return cached;
const input = decodePayload<GenerationPipelineInput>(OPENAPI_PREFIX, serverId);
if (!input?.sourceType) return null;
const pipeline = await runGenerationPipeline(input);
return buildLocalOpenApiPreviewServer(input, pipeline, requestUrl, serverId).server;
}
export async function loadLocalPreviewServer(serverId: string, requestUrl?: string | URL) {
const cached = findLocalGeneratedServer(serverId);
if (cached) return cached;
const website = await loadLocalWebsitePreviewServer(serverId, requestUrl);
if (website) return website;
return loadLocalOpenApiPreviewServer(serverId, requestUrl);
}