| |
|
|
| import { getDbInstance } from "./core"; |
|
|
| interface VersionManagerRow { |
| id?: unknown; |
| tool?: unknown; |
| current_version?: unknown; |
| installed_version?: unknown; |
| pinned_version?: unknown; |
| binary_path?: unknown; |
| status?: unknown; |
| pid?: unknown; |
| port?: unknown; |
| api_key?: unknown; |
| management_key?: unknown; |
| auto_update?: unknown; |
| auto_start?: unknown; |
| last_health_check?: unknown; |
| last_update_check?: unknown; |
| health_status?: unknown; |
| config_overrides?: unknown; |
| error_message?: unknown; |
| created_at?: unknown; |
| updated_at?: unknown; |
| } |
|
|
| function toRecord(value: unknown): Record<string, unknown> { |
| return value && typeof value === "object" ? (value as Record<string, unknown>) : {}; |
| } |
|
|
| function parseConfigOverrides(value: unknown): Record<string, unknown> | null { |
| if (!value || typeof value !== "string" || value.trim() === "") return null; |
| try { |
| const parsed = JSON.parse(value); |
| return typeof parsed === "object" && parsed !== null ? parsed : null; |
| } catch { |
| return null; |
| } |
| } |
|
|
| function stringifyConfigOverrides(value: Record<string, unknown> | null): string | null { |
| if (value === null) return null; |
| try { |
| return JSON.stringify(value); |
| } catch { |
| return null; |
| } |
| } |
|
|
| interface VersionManagerTool { |
| id: number; |
| tool: string; |
| currentVersion: string | null; |
| installedVersion: string | null; |
| pinnedVersion: string | null; |
| binaryPath: string | null; |
| status: string; |
| pid: number | null; |
| port: number; |
| apiKey: string | null; |
| managementKey: string | null; |
| autoUpdate: boolean; |
| autoStart: boolean; |
| lastHealthCheck: string | null; |
| lastUpdateCheck: string | null; |
| healthStatus: string; |
| configOverrides: Record<string, unknown> | null; |
| errorMessage: string | null; |
| createdAt: string; |
| updatedAt: string; |
| } |
|
|
| function rowToVersionManager(row: VersionManagerRow): VersionManagerTool { |
| const record = toRecord(row); |
| return { |
| id: typeof record.id === "number" ? record.id : 0, |
| tool: typeof record.tool === "string" ? record.tool : "", |
| currentVersion: |
| record.current_version === null |
| ? null |
| : typeof record.current_version === "string" |
| ? record.current_version |
| : null, |
| installedVersion: |
| record.installed_version === null |
| ? null |
| : typeof record.installed_version === "string" |
| ? record.installed_version |
| : null, |
| pinnedVersion: |
| record.pinned_version === null |
| ? null |
| : typeof record.pinned_version === "string" |
| ? record.pinned_version |
| : null, |
| binaryPath: |
| record.binary_path === null |
| ? null |
| : typeof record.binary_path === "string" |
| ? record.binary_path |
| : null, |
| status: typeof record.status === "string" ? record.status : "not_installed", |
| pid: record.pid === null ? null : typeof record.pid === "number" ? record.pid : null, |
| port: typeof record.port === "number" ? record.port : 8317, |
| apiKey: |
| record.api_key === null ? null : typeof record.api_key === "string" ? record.api_key : null, |
| managementKey: |
| record.management_key === null |
| ? null |
| : typeof record.management_key === "string" |
| ? record.management_key |
| : null, |
| autoUpdate: |
| record.auto_update === 1 || record.auto_update === true || record.auto_update === "1", |
| autoStart: record.auto_start === 1 || record.auto_start === true || record.auto_start === "1", |
| lastHealthCheck: |
| record.last_health_check === null |
| ? null |
| : typeof record.last_health_check === "string" |
| ? record.last_health_check |
| : null, |
| lastUpdateCheck: |
| record.last_update_check === null |
| ? null |
| : typeof record.last_update_check === "string" |
| ? record.last_update_check |
| : null, |
| healthStatus: typeof record.health_status === "string" ? record.health_status : "unknown", |
| configOverrides: parseConfigOverrides(record.config_overrides), |
| errorMessage: |
| record.error_message === null |
| ? null |
| : typeof record.error_message === "string" |
| ? record.error_message |
| : null, |
| createdAt: typeof record.created_at === "string" ? record.created_at : "", |
| updatedAt: typeof record.updated_at === "string" ? record.updated_at : "", |
| }; |
| } |
|
|
| export async function getVersionManagerStatus(): Promise<VersionManagerTool[]> { |
| const db = getDbInstance(); |
| const rows = db.prepare("SELECT * FROM version_manager").all() as VersionManagerRow[]; |
| return rows.map(rowToVersionManager); |
| } |
|
|
| export async function getVersionManagerTool(tool: string): Promise<VersionManagerTool | null> { |
| const db = getDbInstance(); |
| const row = db.prepare("SELECT * FROM version_manager WHERE tool = ?").get(tool) as |
| | VersionManagerRow |
| | undefined; |
| if (!row) return null; |
| return rowToVersionManager(row); |
| } |
|
|
| export async function upsertVersionManagerTool(data: { |
| tool: string; |
| currentVersion?: string | null; |
| installedVersion?: string | null; |
| pinnedVersion?: string | null; |
| binaryPath?: string | null; |
| status?: string; |
| pid?: number | null; |
| port?: number; |
| apiKey?: string | null; |
| managementKey?: string | null; |
| autoUpdate?: boolean; |
| autoStart?: boolean; |
| healthStatus?: string; |
| configOverrides?: Record<string, unknown> | null; |
| errorMessage?: string | null; |
| }): Promise<VersionManagerTool> { |
| const db = getDbInstance(); |
| db.prepare( |
| ` |
| INSERT INTO version_manager ( |
| tool, current_version, installed_version, pinned_version, binary_path, |
| status, pid, port, api_key, management_key, auto_update, auto_start, |
| health_status, config_overrides, error_message, created_at, updated_at |
| ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), datetime('now')) |
| ON CONFLICT(tool) DO UPDATE SET |
| current_version = excluded.current_version, |
| installed_version = excluded.installed_version, |
| pinned_version = excluded.pinned_version, |
| binary_path = excluded.binary_path, |
| status = excluded.status, |
| pid = excluded.pid, |
| port = excluded.port, |
| api_key = excluded.api_key, |
| management_key = excluded.management_key, |
| auto_update = excluded.auto_update, |
| auto_start = excluded.auto_start, |
| health_status = excluded.health_status, |
| config_overrides = excluded.config_overrides, |
| error_message = excluded.error_message, |
| updated_at = datetime('now') |
| ` |
| ).run( |
| data.tool, |
| data.currentVersion ?? null, |
| data.installedVersion ?? null, |
| data.pinnedVersion ?? null, |
| data.binaryPath ?? null, |
| data.status ?? "not_installed", |
| data.pid ?? null, |
| data.port ?? 8317, |
| data.apiKey ?? null, |
| data.managementKey ?? null, |
| data.autoUpdate !== undefined ? (data.autoUpdate ? 1 : 0) : 1, |
| data.autoStart !== undefined ? (data.autoStart ? 1 : 0) : 0, |
| data.healthStatus ?? "unknown", |
| stringifyConfigOverrides(data.configOverrides ?? null), |
| data.errorMessage ?? null |
| ); |
| const result = await getVersionManagerTool(data.tool); |
| if (!result) throw new Error("Failed to retrieve inserted version manager tool"); |
| return result; |
| } |
|
|
| export async function updateVersionManagerTool( |
| tool: string, |
| updates: Record<string, unknown> |
| ): Promise<VersionManagerTool | null> { |
| const db = getDbInstance(); |
| const existing = await getVersionManagerTool(tool); |
| if (!existing) return null; |
|
|
| const ALLOWED_COLUMNS = new Set([ |
| "currentVersion", |
| "installedVersion", |
| "pinnedVersion", |
| "binaryPath", |
| "status", |
| "pid", |
| "port", |
| "apiKey", |
| "managementKey", |
| "autoUpdate", |
| "autoStart", |
| "healthStatus", |
| "configOverrides", |
| "errorMessage", |
| ]); |
|
|
| const sets: string[] = ["updated_at = datetime('now')"]; |
| const params: Record<string, unknown> = { tool }; |
|
|
| for (const [key, value] of Object.entries(updates)) { |
| if (!ALLOWED_COLUMNS.has(key)) continue; |
| const dbKey = key.replace(/([A-Z])/g, "_$1").toLowerCase(); |
|
|
| if (key === "configOverrides") { |
| sets.push("config_overrides = @configOverrides"); |
| params.configOverrides = stringifyConfigOverrides(value as Record<string, unknown> | null); |
| } else if (key === "autoUpdate" || key === "autoStart") { |
| sets.push(`${dbKey} = @${key}`); |
| params[key] = value === true ? 1 : 0; |
| } else if (value === null) { |
| sets.push(`${dbKey} = null`); |
| } else { |
| sets.push(`${dbKey} = @${key}`); |
| params[key] = value; |
| } |
| } |
|
|
| db.prepare(`UPDATE version_manager SET ${sets.join(", ")} WHERE tool = @tool`).run(params); |
| return getVersionManagerTool(tool); |
| } |
|
|
| export async function deleteVersionManagerTool(tool: string): Promise<boolean> { |
| const db = getDbInstance(); |
| const result = db.prepare("DELETE FROM version_manager WHERE tool = ?").run(tool); |
| return result.changes > 0; |
| } |
|
|
| export async function updateToolHealth(tool: string, healthStatus: string): Promise<boolean> { |
| const db = getDbInstance(); |
| const result = db |
| .prepare( |
| "UPDATE version_manager SET health_status = ?, last_health_check = datetime('now') WHERE tool = ?" |
| ) |
| .run(healthStatus, tool); |
| return result.changes > 0; |
| } |
|
|
| export async function updateToolVersion( |
| tool: string, |
| field: "current_version" | "installed_version", |
| version: string |
| ): Promise<boolean> { |
| const db = getDbInstance(); |
| const result = db |
| .prepare(`UPDATE version_manager SET ${field} = ?, updated_at = datetime('now') WHERE tool = ?`) |
| .run(version, tool); |
| return result.changes > 0; |
| } |
|
|
| export async function setToolStatus( |
| tool: string, |
| status: string, |
| pid?: number, |
| errorMessage?: string |
| ): Promise<boolean> { |
| const db = getDbInstance(); |
| const result = db |
| .prepare( |
| pid !== undefined |
| ? "UPDATE version_manager SET status = ?, pid = ?, error_message = ?, updated_at = datetime('now') WHERE tool = ?" |
| : "UPDATE version_manager SET status = ?, error_message = ?, updated_at = datetime('now') WHERE tool = ?" |
| ) |
| .run( |
| ...(pid !== undefined |
| ? [status, pid, errorMessage ?? null, tool] |
| : [status, errorMessage ?? null, tool]) |
| ); |
| return result.changes > 0; |
| } |
|
|