import { Schema, SchemaAST } from "effect"; import type { JsonSchema } from "effect/JsonSchema"; import type { LiveCatalog, SerializedCatalog } from "./registry"; function getSchemaIdentifier(schema: { ast: SchemaAST.AST }): string | undefined { return SchemaAST.resolveIdentifier(schema.ast); } export function serialize(catalog: LiveCatalog): typeof SerializedCatalog.Type { const defs: Record = {}; function schemaToRef(schema: Schema.Top | undefined): string | undefined { if (!schema) return undefined; const identifier = getSchemaIdentifier(schema); const document = Schema.toJsonSchemaDocument(schema); Object.assign(defs, document.definitions); if (identifier) { return identifier; } // Inline schema without an identifier — store under a generated key const key = `__inline_${Object.keys(defs).length}`; defs[key] = document.schema; return key; } const tools = catalog.tools.map((tool) => ({ path: tool.path, description: tool.description, sourceId: tool.sourceId, input: schemaToRef(tool.input), output: schemaToRef(tool.output), error: schemaToRef(tool.error), })); return { version: "v4.1" as const, types: defs as Record, tools, }; } export function deserializeToJsonSchema(serialized: typeof SerializedCatalog.Type): { tools: ReadonlyArray<{ path: string; description?: string; tags?: ReadonlyArray; namespace?: string; input?: JsonSchema; output?: JsonSchema; error?: JsonSchema; }>; types: Record; } { const types = serialized.types; function resolveRef(ref: string | undefined): JsonSchema | undefined { if (!ref) return undefined; const schema = types[ref]; if (!schema) return undefined; return { ...(schema as JsonSchema), $defs: types as Record, }; } return { tools: serialized.tools.map((tool) => ({ path: tool.path, description: tool.description, sourceId: tool.sourceId, input: resolveRef(tool.input), output: resolveRef(tool.output), error: resolveRef(tool.error), })), types, }; }