feat: add provider-backed microservices
This commit is contained in:
@@ -35,10 +35,46 @@ export interface UniDeskConfig {
|
||||
};
|
||||
};
|
||||
docker: { composeFile: string; projectName: string };
|
||||
microservices: UniDeskMicroserviceConfig[];
|
||||
paths: { stateDir: string; logsDir: string; docsReferenceDir: string };
|
||||
sshForwarding: { mode: string; keyDir: string; host: string; port: number; user: string };
|
||||
}
|
||||
|
||||
export interface UniDeskMicroserviceConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
providerId: string;
|
||||
description: string;
|
||||
repository: {
|
||||
url: string;
|
||||
commitId: string;
|
||||
dockerfile: string;
|
||||
composeFile: string;
|
||||
composeService: string;
|
||||
containerName: string;
|
||||
};
|
||||
backend: {
|
||||
nodeBaseUrl: string;
|
||||
nodeBindHost: string;
|
||||
nodePort: number;
|
||||
proxyMode: string;
|
||||
frontendOnly: boolean;
|
||||
public: boolean;
|
||||
allowedPathPrefixes: string[];
|
||||
healthPath: string;
|
||||
timeoutMs: number;
|
||||
};
|
||||
development: {
|
||||
providerId: string;
|
||||
sshPassthrough: boolean;
|
||||
worktreePath: string;
|
||||
};
|
||||
frontend: {
|
||||
route: string;
|
||||
integrated: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
||||
export const repoRoot = join(moduleDir, "..", "..");
|
||||
|
||||
@@ -70,6 +106,68 @@ function portPair(obj: Record<string, unknown>, key: string): { port: number; co
|
||||
return { port: numberField(value, "port", `network.${key}`), containerPort: numberField(value, "containerPort", `network.${key}`) };
|
||||
}
|
||||
|
||||
function booleanField(obj: Record<string, unknown>, key: string, path: string): boolean {
|
||||
const value = obj[key];
|
||||
if (typeof value !== "boolean") throw new Error(`${path}.${key} must be a boolean`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function optionalArray(value: unknown, name: string): Record<string, unknown>[] {
|
||||
if (value === undefined) return [];
|
||||
if (!Array.isArray(value)) throw new Error(`${name} must be an array`);
|
||||
return value.map((item, index) => asRecord(item, `${name}[${index}]`));
|
||||
}
|
||||
|
||||
function stringArrayField(obj: Record<string, unknown>, key: string, path: string): string[] {
|
||||
const value = obj[key];
|
||||
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item.length === 0)) {
|
||||
throw new Error(`${path}.${key} must be an array of non-empty strings`);
|
||||
}
|
||||
return value as string[];
|
||||
}
|
||||
|
||||
function microserviceConfig(item: Record<string, unknown>, index: number): UniDeskMicroserviceConfig {
|
||||
const path = `microservices[${index}]`;
|
||||
const repository = asRecord(item.repository, `${path}.repository`);
|
||||
const backend = asRecord(item.backend, `${path}.backend`);
|
||||
const development = asRecord(item.development, `${path}.development`);
|
||||
const frontend = asRecord(item.frontend, `${path}.frontend`);
|
||||
return {
|
||||
id: stringField(item, "id", path),
|
||||
name: stringField(item, "name", path),
|
||||
providerId: stringField(item, "providerId", path),
|
||||
description: stringField(item, "description", path),
|
||||
repository: {
|
||||
url: stringField(repository, "url", `${path}.repository`),
|
||||
commitId: stringField(repository, "commitId", `${path}.repository`),
|
||||
dockerfile: stringField(repository, "dockerfile", `${path}.repository`),
|
||||
composeFile: stringField(repository, "composeFile", `${path}.repository`),
|
||||
composeService: stringField(repository, "composeService", `${path}.repository`),
|
||||
containerName: stringField(repository, "containerName", `${path}.repository`),
|
||||
},
|
||||
backend: {
|
||||
nodeBaseUrl: stringField(backend, "nodeBaseUrl", `${path}.backend`),
|
||||
nodeBindHost: stringField(backend, "nodeBindHost", `${path}.backend`),
|
||||
nodePort: numberField(backend, "nodePort", `${path}.backend`),
|
||||
proxyMode: stringField(backend, "proxyMode", `${path}.backend`),
|
||||
frontendOnly: booleanField(backend, "frontendOnly", `${path}.backend`),
|
||||
public: booleanField(backend, "public", `${path}.backend`),
|
||||
allowedPathPrefixes: stringArrayField(backend, "allowedPathPrefixes", `${path}.backend`),
|
||||
healthPath: stringField(backend, "healthPath", `${path}.backend`),
|
||||
timeoutMs: numberField(backend, "timeoutMs", `${path}.backend`),
|
||||
},
|
||||
development: {
|
||||
providerId: stringField(development, "providerId", `${path}.development`),
|
||||
sshPassthrough: booleanField(development, "sshPassthrough", `${path}.development`),
|
||||
worktreePath: stringField(development, "worktreePath", `${path}.development`),
|
||||
},
|
||||
frontend: {
|
||||
route: stringField(frontend, "route", `${path}.frontend`),
|
||||
integrated: booleanField(frontend, "integrated", `${path}.frontend`),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function readConfig(): UniDeskConfig {
|
||||
const configPath = rootPath("config.json");
|
||||
if (!existsSync(configPath)) throw new Error(`config.json not found at ${configPath}`);
|
||||
@@ -82,6 +180,7 @@ export function readConfig(): UniDeskConfig {
|
||||
const auth = asRecord(parsed.auth, "auth");
|
||||
const providerGateway = asRecord(parsed.providerGateway, "providerGateway");
|
||||
const docker = asRecord(parsed.docker, "docker");
|
||||
const microservices = optionalArray(parsed.microservices, "microservices").map(microserviceConfig);
|
||||
const paths = asRecord(parsed.paths, "paths");
|
||||
const sshForwarding = asRecord(parsed.sshForwarding, "sshForwarding");
|
||||
const labels = asRecord(providerGateway.labels, "providerGateway.labels");
|
||||
@@ -129,6 +228,7 @@ export function readConfig(): UniDeskConfig {
|
||||
},
|
||||
},
|
||||
docker: { composeFile: stringField(docker, "composeFile", "docker"), projectName: stringField(docker, "projectName", "docker") },
|
||||
microservices,
|
||||
paths: {
|
||||
stateDir: stringField(paths, "stateDir", "paths"),
|
||||
logsDir: stringField(paths, "logsDir", "paths"),
|
||||
|
||||
Reference in New Issue
Block a user