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
This commit is contained in:
2026-04-21 12:30:36 -07:00
parent b1670c7035
commit 62c52747f5

View File

@@ -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<keyof CoolifyProjectEnvResources> = [
'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<K extends 'applications' | 'databases' | 'services'>(
async function forEachEnv<T>(
projectUuid: string,
key: K
): Promise<NonNullable<CoolifyProjectEnvResources[K]>> {
collect: (envResources: CoolifyProjectEnvResources) => T[]
): Promise<T[]> {
const project = await getProject(projectUuid);
const out: NonNullable<CoolifyProjectEnvResources[K]> = [] 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<K extends 'applications' | 'databases' | '
export async function listApplicationsInProject(
projectUuid: string
): Promise<CoolifyApplication[]> {
return listResourcesInProject(projectUuid, 'applications');
return forEachEnv(projectUuid, r => r.applications ?? []);
}
export async function listDatabasesInProject(
projectUuid: string
): Promise<CoolifyDatabase[]> {
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<CoolifyService[]> {
return listResourcesInProject(projectUuid, 'services');
return forEachEnv(projectUuid, r => r.services ?? []);
}
/** @deprecated Use getApplicationInProject / ensureResourceInProject instead. */