feat: implement metadata catalog database management
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
} from "./auth/config.js";
|
||||
import { createProjectedAuthenticationConfigProvider } from "./auth/runtime-projection.js";
|
||||
import type { WorkspaceRegistryConfig } from "./workspaces/types.js";
|
||||
import type { CatalogConnectionConfig } from "./catalog/repository.js";
|
||||
|
||||
export interface AppConfig {
|
||||
host: string; port: number; harnessDir: string; thtBin: string; piBin: string;
|
||||
@@ -20,6 +21,8 @@ export interface AppConfig {
|
||||
host?: string; port?: number; database?: string; runtimeUser?: string;
|
||||
runtimePasswordFile?: string; sslmode?: "verify-ca" | "verify-full"; sslrootcert?: string;
|
||||
};
|
||||
/** Installation-local metadata catalog. Omitted installations expose an unavailable admin surface. */
|
||||
catalogDatabase?: CatalogConnectionConfig;
|
||||
defaults: { provider?: string; model?: string; thinking?: string };
|
||||
maxPiProcesses: number;
|
||||
settingsFile: string;
|
||||
@@ -40,6 +43,7 @@ export interface AppConfig {
|
||||
/** Explicit compatibility mode for old loopback clients that send `workspace` in POST /sessions. */
|
||||
legacyWorkspaceMode: boolean;
|
||||
workspaceDiagnosticTimeoutMs: number;
|
||||
catalogSyncTimeoutMs: number;
|
||||
workspaceRegistry: WorkspaceRegistryConfig;
|
||||
workspaceSecretStoreRoot: string;
|
||||
workspaceSecretRuntimeRoot: string;
|
||||
@@ -127,6 +131,14 @@ function diagnosticTimeout(value: string | undefined): number {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
function catalogSyncTimeout(value: string | undefined): number {
|
||||
const timeout = Number(value ?? 600_000);
|
||||
if (!Number.isSafeInteger(timeout) || timeout < 1_000 || timeout > 3_600_000) {
|
||||
throw new Error("catalog synchronization timeout configuration is invalid");
|
||||
}
|
||||
return timeout;
|
||||
}
|
||||
|
||||
function piManagementTimeout(value: string | undefined): number {
|
||||
const timeout = Number(value ?? 8_000);
|
||||
if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 30_000) {
|
||||
@@ -176,6 +188,33 @@ function positiveDimension(value: string | undefined, fallback: number): number
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function catalogDatabase(env: Record<string, string | undefined>): CatalogConnectionConfig | undefined {
|
||||
const value = env.THT_CATALOG_DATABASE_URL;
|
||||
if (value !== undefined) {
|
||||
try {
|
||||
const parsed = new URL(value);
|
||||
if ((parsed.protocol !== "postgres:" && parsed.protocol !== "postgresql:")
|
||||
|| !parsed.hostname || !parsed.pathname.slice(1) || parsed.hash || parsed.search) throw new Error();
|
||||
return { connectionString: value };
|
||||
} catch {
|
||||
throw new Error("catalog database configuration is invalid");
|
||||
}
|
||||
}
|
||||
const host = env.THT_CATALOG_DB_HOST;
|
||||
if (host === undefined) return undefined;
|
||||
const port = Number(env.THT_CATALOG_DB_PORT ?? 5432);
|
||||
const database = env.THT_CATALOG_DB_NAME;
|
||||
const user = env.THT_CATALOG_RUNTIME_USER;
|
||||
const passwordFile = env.THT_CATALOG_RUNTIME_PASSWORD_FILE;
|
||||
try {
|
||||
if (!host.trim() || !database?.trim() || !user?.trim() || !passwordFile
|
||||
|| !path.isAbsolute(passwordFile) || !Number.isInteger(port) || port < 1 || port > 65_535) throw new Error();
|
||||
return { host, port, database, user, passwordFile };
|
||||
} catch {
|
||||
throw new Error("catalog database configuration is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
export function loadConfig(
|
||||
env: Record<string, string | undefined>,
|
||||
options: { surface?: "application" | "workspace-maintenance" } = {},
|
||||
@@ -356,6 +395,7 @@ export function loadConfig(
|
||||
authentication,
|
||||
publicExposure,
|
||||
sessionStorage,
|
||||
catalogDatabase: catalogDatabase(env),
|
||||
defaults: { provider: env.PI_PROVIDER, model: env.PI_MODEL, thinking: env.PI_THINKING },
|
||||
maxPiProcesses: Number(env.MAX_PI_PROCESSES ?? 4),
|
||||
settingsFile,
|
||||
@@ -370,6 +410,7 @@ export function loadConfig(
|
||||
dwhPrecheck: env.THT_DWH_PRECHECK === "true" || env.THT_DWH_PRECHECK === "1",
|
||||
legacyWorkspaceMode: legacyWorkspaceMode === "local",
|
||||
workspaceDiagnosticTimeoutMs: diagnosticTimeout(env.THT_WORKSPACE_DIAGNOSTIC_TIMEOUT_MS),
|
||||
catalogSyncTimeoutMs: catalogSyncTimeout(env.THT_CATALOG_SYNC_TIMEOUT_MS),
|
||||
workspaceRegistry,
|
||||
workspaceSecretStoreRoot,
|
||||
workspaceSecretRuntimeRoot,
|
||||
|
||||
Reference in New Issue
Block a user