feat: add canonical workspace schema

This commit is contained in:
2026-08-03 21:31:07 +02:00
parent 6434c9c4e1
commit 92cb0545be
4 changed files with 414 additions and 0 deletions
+146
View File
@@ -0,0 +1,146 @@
import type { CanonicalWorkspace, DwhTransport, VectorTransport } from "./schema.js";
export type InstallationRole = "DWH" | "VECTOR" | "EMBEDDING";
export type InstallationSuffix =
| "TRANSPORT"
| "HOST"
| "PORT"
| "BASE_URL"
| "USER"
| "PASSWORD_FILE"
| "API_KEY_FILE"
| "TLS_CA_FILE"
| "SSH_HOST"
| "SSH_PORT"
| "SSH_USER"
| "SSH_PRIVATE_KEY_FILE"
| "SSH_KNOWN_HOSTS_FILE"
| "SSH_TARGET_HOST"
| "SSH_TARGET_PORT";
type ConnectorTransport = DwhTransport | VectorTransport;
export interface InstallationVariable {
name: string;
role: InstallationRole;
suffix: InstallationSuffix;
secret: boolean;
transports?: readonly ConnectorTransport[];
}
export interface InstallationContract {
workspaceId: string;
namespace: string;
variables: InstallationVariable[];
}
const CONNECTOR_SUFFIXES: readonly InstallationSuffix[] = [
"TRANSPORT",
"HOST",
"PORT",
"BASE_URL",
"USER",
"PASSWORD_FILE",
"API_KEY_FILE",
"TLS_CA_FILE",
"SSH_HOST",
"SSH_PORT",
"SSH_USER",
"SSH_PRIVATE_KEY_FILE",
"SSH_KNOWN_HOSTS_FILE",
"SSH_TARGET_HOST",
"SSH_TARGET_PORT",
];
const EMBEDDING_SUFFIXES: readonly InstallationSuffix[] = [
"BASE_URL",
"API_KEY_FILE",
"TLS_CA_FILE",
];
function namespaceFor(workspace: CanonicalWorkspace): string {
return workspace.workspace.id.replaceAll("-", "_").toUpperCase();
}
function createVariable(
namespace: string,
role: InstallationRole,
suffix: InstallationSuffix,
transports?: readonly ConnectorTransport[],
): InstallationVariable {
return {
name: `THT_WS_${namespace}_${role}_${suffix}`,
role,
suffix,
secret: suffix.endsWith("_FILE"),
...(transports ? { transports } : {}),
};
}
function connectorVariables(
namespace: string,
role: "DWH" | "VECTOR",
transports: readonly ConnectorTransport[],
): InstallationVariable[] {
return CONNECTOR_SUFFIXES.map((suffix) => createVariable(namespace, role, suffix, transports));
}
export function buildInstallationContract(workspace: CanonicalWorkspace): InstallationContract {
const namespace = namespaceFor(workspace);
return {
workspaceId: workspace.workspace.id,
namespace,
variables: [
...connectorVariables(namespace, "DWH", workspace.dwh.supported_transports),
...connectorVariables(
namespace,
"VECTOR",
workspace.semantic_index.vector_store.supported_transports,
),
...EMBEDDING_SUFFIXES.map((suffix) => createVariable(namespace, "EMBEDDING", suffix)),
],
};
}
function localizedIntroduction(workspace: CanonicalWorkspace): string {
return workspace.workspace.language === "it"
? `Configurazione dell'installazione per ${workspace.workspace.name}. Imposta solo i binding supportati da questa installazione.`
: `Installation setup for ${workspace.workspace.name}. Configure only the bindings supported by this installation.`;
}
export function renderWorkspaceDocs(workspace: CanonicalWorkspace): { envExample: string; markdown: string } {
const contract = buildInstallationContract(workspace);
const variablesByRole = new Map<InstallationRole, InstallationVariable[]>();
for (const variable of contract.variables) {
const variables = variablesByRole.get(variable.role) ?? [];
variables.push(variable);
variablesByRole.set(variable.role, variables);
}
const envExample = [
`# Generated installation bindings for ${workspace.workspace.id}`,
"# Provide secret file paths only; never paste secret values here.",
...contract.variables.map((variable) => `${variable.name}=`),
"",
].join("\n");
const markdown = [
"# Installation requirements",
"",
`**Workspace:** ${workspace.workspace.name}`,
"",
localizedIntroduction(workspace),
"",
"Use the following UI fields as installation bindings. Secret fields always contain file paths, never secret values.",
"",
...(["DWH", "VECTOR", "EMBEDDING"] as const).flatMap((role) => [
`## ${role === "DWH" ? "Data warehouse" : role === "VECTOR" ? "Vector store" : "Embedding service"}`,
"",
...(variablesByRole.get(role) ?? []).map((variable) => `- \`${variable.name}\``),
"",
]),
].join("\n");
return { envExample, markdown };
}