Files
dokploy/packages/server/src/templates/github.ts
T
Mauricio Siu 6e1d020769 feat(icon): enhance icon management for services
- Updated ShowIconSettings component to handle both application and compose service types.
- Added new icon column to the compose table in the database.
- Implemented fetching and updating of icons for services in the environment and application pages.
- Introduced fetchTemplateLogo function to retrieve logos for templates, improving icon handling for compose services.
2026-07-28 15:50:43 -06:00

150 lines
3.5 KiB
TypeScript

import { parse } from "toml";
/**
* Complete template interface that includes both metadata and configuration
*/
export interface CompleteTemplate {
metadata: {
id: string;
name: string;
description: string;
tags: string[];
version: string;
logo: string;
links: {
github: string;
website?: string;
docs?: string;
};
};
variables: {
[key: string]: string;
};
config: {
isolated?: boolean;
domains: Array<{
serviceName: string;
port: number;
path?: string;
host?: string;
}>;
env: Record<string, string>;
mounts?: Array<{
filePath: string;
content: string;
}>;
};
}
interface TemplateMetadata {
id: string;
name: string;
description: string;
version: string;
logo: string;
links: {
github: string;
website?: string;
docs?: string;
};
tags: string[];
}
/**
* Fetches the list of available templates from meta.json
*/
export async function fetchTemplatesList(
baseUrl = "https://templates.dokploy.com",
): Promise<TemplateMetadata[]> {
const response = await fetch(`${baseUrl}/meta.json`, {
signal: AbortSignal.timeout(10000),
});
if (!response.ok) {
throw new Error(`Failed to fetch templates: ${response.statusText}`);
}
const templates = (await response.json()) as TemplateMetadata[];
return templates.map((template) => ({
id: template.id,
name: template.name,
description: template.description,
version: template.version,
logo: template.logo,
links: template.links,
tags: template.tags,
}));
}
const LOGO_MIME_TYPES: Record<string, string> = {
png: "image/png",
jpg: "image/jpeg",
jpeg: "image/jpeg",
svg: "image/svg+xml",
webp: "image/webp",
gif: "image/gif",
};
export async function fetchTemplateLogo(
templateId: string,
baseUrl = "https://templates.dokploy.com",
): Promise<string | null> {
try {
const templates = await fetchTemplatesList(baseUrl);
const template = templates.find((t) => t.id === templateId);
if (!template?.logo) return null;
const response = await fetch(
`${baseUrl}/blueprints/${templateId}/${template.logo}`,
{ signal: AbortSignal.timeout(10000) },
);
if (!response.ok) return null;
const buffer = Buffer.from(await response.arrayBuffer());
if (buffer.length === 0) return null;
const contentType = response.headers.get("content-type")?.split(";")[0];
const extension = template.logo.split(".").pop()?.toLowerCase() ?? "";
const mimeType = contentType?.startsWith("image/")
? contentType
: LOGO_MIME_TYPES[extension];
if (!mimeType) return null;
const dataUrl = `data:${mimeType};base64,${buffer.toString("base64")}`;
if (dataUrl.length > 2 * 1024 * 1024) return null;
return dataUrl;
} catch {
return null;
}
}
/**
* Fetches a specific template's files
*/
export async function fetchTemplateFiles(
templateId: string,
baseUrl = "https://templates.dokploy.com",
): Promise<{ config: CompleteTemplate; dockerCompose: string }> {
const timeout = AbortSignal.timeout(10000);
const [templateYmlResponse, dockerComposeResponse] = await Promise.all([
fetch(`${baseUrl}/blueprints/${templateId}/template.toml`, {
signal: timeout,
}),
fetch(`${baseUrl}/blueprints/${templateId}/docker-compose.yml`, {
signal: timeout,
}),
]);
if (!templateYmlResponse.ok || !dockerComposeResponse.ok) {
throw new Error("Template files not found");
}
const [templateYml, dockerCompose] = await Promise.all([
templateYmlResponse.text(),
dockerComposeResponse.text(),
]);
const config = parse(templateYml) as CompleteTemplate;
return { config, dockerCompose };
}