Skip to main content
Glama
RefreshVersionTool.ts3.51 kB
import * as semver from "semver"; import type { IPipeline } from "../pipeline/trpc/interfaces"; import { logger } from "../utils/logger"; import { ValidationError } from "./errors"; export interface RefreshVersionToolOptions { library: string; version?: string | null; // Make version optional /** If false, returns jobId immediately without waiting. Defaults to true. */ waitForCompletion?: boolean; } export interface RefreshResult { /** Indicates the number of pages refreshed if waitForCompletion was true and the job succeeded. May be 0 or inaccurate if job failed or waitForCompletion was false. */ pagesRefreshed: number; } /** Return type for RefreshVersionTool.execute */ export type RefreshExecuteResult = RefreshResult | { jobId: string }; /** * Tool for refreshing an existing library version by re-scraping all pages * and using ETag comparison to skip unchanged content. */ export class RefreshVersionTool { private pipeline: IPipeline; constructor(pipeline: IPipeline) { this.pipeline = pipeline; } async execute(options: RefreshVersionToolOptions): Promise<RefreshExecuteResult> { const { library, version, waitForCompletion = true } = options; let internalVersion: string; const partialVersionRegex = /^\d+(\.\d+)?$/; // Matches '1' or '1.2' if (version === null || version === undefined) { internalVersion = ""; } else { const validFullVersion = semver.valid(version); if (validFullVersion) { internalVersion = validFullVersion; } else if (partialVersionRegex.test(version)) { const coercedVersion = semver.coerce(version); if (coercedVersion) { internalVersion = coercedVersion.version; } else { throw new ValidationError( `Invalid version format for refreshing: '${version}'. Use 'X.Y.Z', 'X.Y.Z-prerelease', 'X.Y', 'X', or omit.`, "RefreshVersionTool", ); } } else { throw new ValidationError( `Invalid version format for refreshing: '${version}'. Use 'X.Y.Z', 'X.Y.Z-prerelease', 'X.Y', 'X', or omit.`, "RefreshVersionTool", ); } } internalVersion = internalVersion.toLowerCase(); // Use the injected pipeline instance const pipeline = this.pipeline; // Normalize pipeline version argument: use null for unversioned to be explicit cross-platform const refreshVersion: string | null = internalVersion === "" ? null : internalVersion; // Enqueue the refresh job using the injected pipeline const jobId = await pipeline.enqueueRefreshJob(library, refreshVersion); // Conditionally wait for completion if (waitForCompletion) { try { await pipeline.waitForJobCompletion(jobId); // Fetch final job state to get status and potentially final page count const finalJob = await pipeline.getJob(jobId); const finalPagesRefreshed = finalJob?.progress?.pagesScraped ?? 0; // Get count from final job state logger.debug( `Refresh job ${jobId} finished with status ${finalJob?.status}. Pages refreshed: ${finalPagesRefreshed}`, ); return { pagesRefreshed: finalPagesRefreshed, }; } catch (error) { logger.error(`❌ Refresh job ${jobId} failed or was cancelled: ${error}`); throw error; // Re-throw so the caller knows it failed } } // If not waiting, return the job ID immediately return { jobId }; } }

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