diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index d395bdffc..0398b6ba9 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -700,11 +700,14 @@ export const composeRouter = createTRPCRouter({ getTags: protectedProcedure .input(z.object({ baseUrl: z.string().optional() })) .query(async ({ input }) => { - const githubTemplates = await fetchTemplatesList(input.baseUrl); - - const allTags = githubTemplates.flatMap((template) => template.tags); - const uniqueTags = _.uniq(allTags); - return uniqueTags; + try { + const githubTemplates = await fetchTemplatesList(input.baseUrl); + const allTags = githubTemplates.flatMap((template) => template.tags); + return _.uniq(allTags); + } catch (error) { + console.warn("Failed to fetch template tags:", error); + return []; + } }), disconnectGitProvider: protectedProcedure .input(apiFindCompose) diff --git a/packages/server/src/templates/github.ts b/packages/server/src/templates/github.ts index a935b2155..da697d80c 100644 --- a/packages/server/src/templates/github.ts +++ b/packages/server/src/templates/github.ts @@ -55,25 +55,22 @@ interface TemplateMetadata { export async function fetchTemplatesList( baseUrl = "https://templates.dokploy.com", ): Promise { - try { - const response = await fetch(`${baseUrl}/meta.json`); - 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, - })); - } catch (error) { - console.error("Error fetching templates list:", error); - throw error; + 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, + })); } /** @@ -83,27 +80,26 @@ export async function fetchTemplateFiles( templateId: string, baseUrl = "https://templates.dokploy.com", ): Promise<{ config: CompleteTemplate; dockerCompose: string }> { - try { - // Fetch both files in parallel - const [templateYmlResponse, dockerComposeResponse] = await Promise.all([ - fetch(`${baseUrl}/blueprints/${templateId}/template.toml`), - fetch(`${baseUrl}/blueprints/${templateId}/docker-compose.yml`), - ]); + 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 }; - } catch (error) { - console.error(`Error fetching template ${templateId}:`, error); - throw error; + 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 }; }