Skip to main content
Glama
router.ts7.18 kB
/** * tRPC router exposing document data store operations via the worker API. * Only procedures actually used externally are included to keep surface minimal. */ import { initTRPC } from "@trpc/server"; import superjson from "superjson"; import { z } from "zod"; import type { DbVersionWithLibrary, FindVersionResult, StoreSearchResult, VersionStatus, } from "../types"; import type { IDocumentManagement } from "./interfaces"; // Context carries the document management API export interface DataTrpcContext { docService: IDocumentManagement; } const t = initTRPC.context<DataTrpcContext>().create({ transformer: superjson, }); // Common schemas const nonEmpty = z .string() .min(1) .transform((s) => s.trim()); const optionalVersion = z .string() .optional() .nullable() .transform((v) => (typeof v === "string" ? v.trim() : v)); export function createDataRouter(trpc: unknown) { const tt = trpc as typeof t; return tt.router({ ping: tt.procedure.query(async () => ({ status: "ok", ts: Date.now() })), listLibraries: tt.procedure.query(async ({ ctx }: { ctx: DataTrpcContext }) => { return await ctx.docService.listLibraries(); // LibrarySummary[] }), findBestVersion: tt.procedure .input(z.object({ library: nonEmpty, targetVersion: z.string().optional() })) .query( async ({ ctx, input, }: { ctx: DataTrpcContext; input: { library: string; targetVersion?: string }; }) => { const result = await ctx.docService.findBestVersion( input.library, input.targetVersion, ); return result as FindVersionResult; }, ), validateLibraryExists: tt.procedure .input(z.object({ library: nonEmpty })) .mutation( async ({ ctx, input }: { ctx: DataTrpcContext; input: { library: string } }) => { await ctx.docService.validateLibraryExists(input.library); return { ok: true } as const; }, ), search: tt.procedure .input( z.object({ library: nonEmpty, version: optionalVersion, query: nonEmpty, limit: z.number().int().positive().max(50).optional(), }), ) .query( async ({ ctx, input, }: { ctx: DataTrpcContext; input: { library: string; version: string | null | undefined; query: string; limit?: number; }; }) => { const results = await ctx.docService.searchStore( input.library, input.version ?? null, input.query, input.limit ?? 5, ); return results as StoreSearchResult[]; }, ), removeVersion: tt.procedure .input(z.object({ library: nonEmpty, version: optionalVersion })) .mutation( async ({ ctx, input, }: { ctx: DataTrpcContext; input: { library: string; version: string | null | undefined }; }) => { await ctx.docService.removeVersion(input.library, input.version ?? null); return { ok: true } as const; }, ), removeAllDocuments: tt.procedure .input(z.object({ library: nonEmpty, version: optionalVersion })) .mutation( async ({ ctx, input, }: { ctx: DataTrpcContext; input: { library: string; version: string | null | undefined }; }) => { await ctx.docService.removeAllDocuments(input.library, input.version ?? null); return { ok: true } as const; }, ), // Status and version helpers getVersionsByStatus: tt.procedure .input(z.object({ statuses: z.array(z.string()) })) .query( async ({ ctx, input, }: { ctx: DataTrpcContext; input: { statuses: string[] }; }) => { // Cast trusting caller to pass valid VersionStatus strings const statuses = input.statuses as unknown as VersionStatus[]; return (await ctx.docService.getVersionsByStatus( statuses, )) as DbVersionWithLibrary[]; }, ), findVersionsBySourceUrl: tt.procedure .input(z.object({ url: nonEmpty })) .query(async ({ ctx, input }: { ctx: DataTrpcContext; input: { url: string } }) => { return (await ctx.docService.findVersionsBySourceUrl( input.url, )) as DbVersionWithLibrary[]; }), getScraperOptions: tt.procedure .input(z.object({ versionId: z.number().int().positive() })) .query( async ({ ctx, input, }: { ctx: DataTrpcContext; input: { versionId: number }; }) => { return await ctx.docService.getScraperOptions(input.versionId); }, ), updateVersionStatus: tt.procedure .input( z.object({ versionId: z.number().int().positive(), status: z.string(), errorMessage: z.string().optional().nullable(), }), ) .mutation( async ({ ctx, input, }: { ctx: DataTrpcContext; input: { versionId: number; status: string; errorMessage?: string | null }; }) => { await ctx.docService.updateVersionStatus( input.versionId, input.status as VersionStatus, input.errorMessage ?? undefined, ); return { ok: true } as const; }, ), updateVersionProgress: tt.procedure .input( z.object({ versionId: z.number().int().positive(), pages: z.number().int().nonnegative(), maxPages: z.number().int().positive(), }), ) .mutation( async ({ ctx, input, }: { ctx: DataTrpcContext; input: { versionId: number; pages: number; maxPages: number }; }) => { await ctx.docService.updateVersionProgress( input.versionId, input.pages, input.maxPages, ); return { ok: true } as const; }, ), storeScraperOptions: tt.procedure .input( z.object({ versionId: z.number().int().positive(), options: z.unknown(), }), ) .mutation( async ({ ctx, input, }: { ctx: DataTrpcContext; input: { versionId: number; options: unknown }; }) => { // options conforms to ScraperOptions at the caller; keep as unknown here await ctx.docService.storeScraperOptions( input.versionId, input.options as unknown as Parameters< IDocumentManagement["storeScraperOptions"] >[1], ); return { ok: true } as const; }, ), }); } // Default router for standalone usage export const dataRouter = createDataRouter(t); export type DataRouter = typeof dataRouter;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/arabold/docs-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server