From 62c52747f559873355c5f65bd764a7cbf9a91b44 Mon Sep 17 00:00:00 2001 From: Mark Henderson Date: Tue, 21 Apr 2026 12:30:36 -0700 Subject: [PATCH] fix(coolify): list project databases across per-flavor arrays GET /projects/{uuid}/{envName} returns databases split into postgresqls/mysqls/mariadbs/mongodbs/redis/keydbs/dragonflies/clickhouses sibling arrays instead of a unified `databases` list. Combine all of them in listDatabasesInProject. Also normalize setApplicationDomains to prepend https:// on bare hostnames (Coolify validates as URL). Made-with: Cursor --- lib/coolify.ts | 63 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/lib/coolify.ts b/lib/coolify.ts index 1203c9d..ad0a979 100644 --- a/lib/coolify.ts +++ b/lib/coolify.ts @@ -402,8 +402,14 @@ export async function setApplicationDomains( domains: string[], opts: { forceOverride?: boolean } = {} ): Promise<{ uuid: string }> { + // Coolify validates each entry as a URL, so bare hostnames need a scheme. + const normalized = domains.map(d => { + const trimmed = d.trim(); + if (/^https?:\/\//i.test(trimmed)) return trimmed; + return `https://${trimmed}`; + }); return updateApplication(uuid, { - domains: domains.join(','), + domains: normalized.join(','), force_domain_override: opts.forceOverride ?? true, is_force_https_enabled: true, }); @@ -710,16 +716,37 @@ export async function getServiceInProject( return svc; } -/** Response shape of GET /projects/{uuid}/{envName}. */ +/** + * Response shape of GET /projects/{uuid}/{envName}. + * Coolify splits databases by flavor across sibling arrays. + */ interface CoolifyProjectEnvResources { id: number; uuid: string; name: string; applications?: CoolifyApplication[]; - databases?: CoolifyDatabase[]; services?: CoolifyService[]; + postgresqls?: CoolifyDatabase[]; + mysqls?: CoolifyDatabase[]; + mariadbs?: CoolifyDatabase[]; + mongodbs?: CoolifyDatabase[]; + redis?: CoolifyDatabase[]; + keydbs?: CoolifyDatabase[]; + dragonflies?: CoolifyDatabase[]; + clickhouses?: CoolifyDatabase[]; } +const DB_ARRAY_KEYS: Array = [ + 'postgresqls', + 'mysqls', + 'mariadbs', + 'mongodbs', + 'redis', + 'keydbs', + 'dragonflies', + 'clickhouses', +]; + async function getProjectEnvResources( projectUuid: string, envName: string @@ -727,22 +754,15 @@ async function getProjectEnvResources( return coolifyFetch(`/projects/${projectUuid}/${encodeURIComponent(envName)}`); } -/** - * List all apps/dbs/services across all environments of a project. - * Uses one `/projects/{uuid}` call + one call per environment. - */ -async function listResourcesInProject( +async function forEachEnv( projectUuid: string, - key: K -): Promise> { + collect: (envResources: CoolifyProjectEnvResources) => T[] +): Promise { const project = await getProject(projectUuid); - const out: NonNullable = [] as never; + const out: T[] = []; for (const env of project.environments ?? []) { const envResources = await getProjectEnvResources(projectUuid, env.name); - const list = envResources[key]; - if (Array.isArray(list)) { - (out as unknown[]).push(...list); - } + out.push(...collect(envResources)); } return out; } @@ -750,19 +770,26 @@ async function listResourcesInProject { - return listResourcesInProject(projectUuid, 'applications'); + return forEachEnv(projectUuid, r => r.applications ?? []); } export async function listDatabasesInProject( projectUuid: string ): Promise { - return listResourcesInProject(projectUuid, 'databases'); + return forEachEnv(projectUuid, r => { + const out: CoolifyDatabase[] = []; + for (const k of DB_ARRAY_KEYS) { + const arr = r[k]; + if (Array.isArray(arr)) out.push(...(arr as CoolifyDatabase[])); + } + return out; + }); } export async function listServicesInProject( projectUuid: string ): Promise { - return listResourcesInProject(projectUuid, 'services'); + return forEachEnv(projectUuid, r => r.services ?? []); } /** @deprecated Use getApplicationInProject / ensureResourceInProject instead. */