Merge pull request #293 from dominicbachmann/improve-typing
Started to introduce more typing
This commit is contained in:
		@@ -1,9 +1,17 @@
 | 
			
		||||
async function send({ method, path, data = {}, headers, timeout = 30000 }) {
 | 
			
		||||
// TODO: Make this functions generic
 | 
			
		||||
 | 
			
		||||
async function send({
 | 
			
		||||
	method,
 | 
			
		||||
	path,
 | 
			
		||||
	data = {},
 | 
			
		||||
	headers,
 | 
			
		||||
	timeout = 30000
 | 
			
		||||
}): Promise<Record<string, unknown>> {
 | 
			
		||||
	const controller = new AbortController();
 | 
			
		||||
	const id = setTimeout(() => controller.abort(), timeout);
 | 
			
		||||
	const opts = { method, headers: {}, body: null, signal: controller.signal };
 | 
			
		||||
	if (Object.keys(data).length > 0) {
 | 
			
		||||
		let parsedData = data;
 | 
			
		||||
		const parsedData = data;
 | 
			
		||||
		for (const [key, value] of Object.entries(data)) {
 | 
			
		||||
			if (value === '') {
 | 
			
		||||
				parsedData[key] = null;
 | 
			
		||||
@@ -43,18 +51,33 @@ async function send({ method, path, data = {}, headers, timeout = 30000 }) {
 | 
			
		||||
	return responseData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function get(path, headers = {}): Promise<any> {
 | 
			
		||||
export function get(
 | 
			
		||||
	path: string,
 | 
			
		||||
	headers: Record<string, unknown>
 | 
			
		||||
): Promise<Record<string, unknown>> {
 | 
			
		||||
	return send({ method: 'GET', path, headers });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function del(path, data = {}, headers = {}): Promise<any> {
 | 
			
		||||
export function del(
 | 
			
		||||
	path: string,
 | 
			
		||||
	data: Record<string, unknown>,
 | 
			
		||||
	headers: Record<string, unknown>
 | 
			
		||||
): Promise<Record<string, unknown>> {
 | 
			
		||||
	return send({ method: 'DELETE', path, data, headers });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function post(path, data, headers = {}): Promise<any> {
 | 
			
		||||
export function post(
 | 
			
		||||
	path: string,
 | 
			
		||||
	data: Record<string, unknown>,
 | 
			
		||||
	headers: Record<string, unknown>
 | 
			
		||||
): Promise<Record<string, unknown>> {
 | 
			
		||||
	return send({ method: 'POST', path, data, headers });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function put(path, data, headers = {}): Promise<any> {
 | 
			
		||||
export function put(
 | 
			
		||||
	path: string,
 | 
			
		||||
	data: Record<string, unknown>,
 | 
			
		||||
	headers: Record<string, unknown>
 | 
			
		||||
): Promise<Record<string, unknown>> {
 | 
			
		||||
	return send({ method: 'PUT', path, data, headers });
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,8 @@ import { version as currentVersion } from '../../package.json';
 | 
			
		||||
import dayjs from 'dayjs';
 | 
			
		||||
import Cookie from 'cookie';
 | 
			
		||||
import os from 'os';
 | 
			
		||||
import cuid from 'cuid';
 | 
			
		||||
import type { RequestEvent } from '@sveltejs/kit/types/internal';
 | 
			
		||||
import type { Job } from 'bullmq';
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
	if (!dev) {
 | 
			
		||||
@@ -45,13 +46,21 @@ const customConfig: Config = {
 | 
			
		||||
 | 
			
		||||
export const version = currentVersion;
 | 
			
		||||
export const asyncExecShell = util.promisify(child.exec);
 | 
			
		||||
export const asyncSleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay));
 | 
			
		||||
 | 
			
		||||
export const asyncSleep = (delay: number): Promise<unknown> =>
 | 
			
		||||
	new Promise((resolve) => setTimeout(resolve, delay));
 | 
			
		||||
export const sentry = Sentry;
 | 
			
		||||
 | 
			
		||||
export const uniqueName = () => uniqueNamesGenerator(customConfig);
 | 
			
		||||
export const uniqueName = (): string => uniqueNamesGenerator(customConfig);
 | 
			
		||||
 | 
			
		||||
export const saveBuildLog = async ({ line, buildId, applicationId }) => {
 | 
			
		||||
export const saveBuildLog = async ({
 | 
			
		||||
	line,
 | 
			
		||||
	buildId,
 | 
			
		||||
	applicationId
 | 
			
		||||
}: {
 | 
			
		||||
	line: string;
 | 
			
		||||
	buildId: string;
 | 
			
		||||
	applicationId: string;
 | 
			
		||||
}): Promise<Job> => {
 | 
			
		||||
	if (line) {
 | 
			
		||||
		if (line.includes('ghs_')) {
 | 
			
		||||
			const regex = /ghs_.*@/g;
 | 
			
		||||
@@ -62,20 +71,7 @@ export const saveBuildLog = async ({ line, buildId, applicationId }) => {
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const isTeamIdTokenAvailable = (request) => {
 | 
			
		||||
	const cookie = request.headers.cookie
 | 
			
		||||
		?.split(';')
 | 
			
		||||
		.map((s) => s.trim())
 | 
			
		||||
		.find((s) => s.startsWith('teamId='))
 | 
			
		||||
		?.split('=')[1];
 | 
			
		||||
	if (!cookie) {
 | 
			
		||||
		return getTeam(request);
 | 
			
		||||
	} else {
 | 
			
		||||
		return cookie;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getTeam = (event) => {
 | 
			
		||||
export const getTeam = (event: RequestEvent): string | null => {
 | 
			
		||||
	const cookies = Cookie.parse(event.request.headers.get('cookie'));
 | 
			
		||||
	if (cookies?.teamId) {
 | 
			
		||||
		return cookies.teamId;
 | 
			
		||||
@@ -85,7 +81,16 @@ export const getTeam = (event) => {
 | 
			
		||||
	return null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getUserDetails = async (event, isAdminRequired = true) => {
 | 
			
		||||
export const getUserDetails = async (
 | 
			
		||||
	event: RequestEvent,
 | 
			
		||||
	isAdminRequired = true
 | 
			
		||||
): Promise<{
 | 
			
		||||
	teamId: string;
 | 
			
		||||
	userId: string;
 | 
			
		||||
	permission: string;
 | 
			
		||||
	status: number;
 | 
			
		||||
	body: { message: string };
 | 
			
		||||
}> => {
 | 
			
		||||
	const teamId = getTeam(event);
 | 
			
		||||
	const userId = event?.locals?.session?.data?.userId || null;
 | 
			
		||||
	const { permission = 'read' } = await db.prisma.permission.findFirst({
 | 
			
		||||
@@ -112,11 +117,11 @@ export const getUserDetails = async (event, isAdminRequired = true) => {
 | 
			
		||||
	return payload;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function getEngine(engine) {
 | 
			
		||||
export function getEngine(engine: string): string {
 | 
			
		||||
	return engine === '/var/run/docker.sock' ? 'unix:///var/run/docker.sock' : engine;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function removeContainer(id, engine) {
 | 
			
		||||
export async function removeContainer(id: string, engine: string): Promise<void> {
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
	try {
 | 
			
		||||
		const { stdout } = await asyncExecShell(
 | 
			
		||||
@@ -132,11 +137,23 @@ export async function removeContainer(id, engine) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const removeDestinationDocker = async ({ id, engine }) => {
 | 
			
		||||
export const removeDestinationDocker = async ({
 | 
			
		||||
	id,
 | 
			
		||||
	engine
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	engine: string;
 | 
			
		||||
}): Promise<void> => {
 | 
			
		||||
	return await removeContainer(id, engine);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const createDirectories = async ({ repository, buildId }) => {
 | 
			
		||||
export const createDirectories = async ({
 | 
			
		||||
	repository,
 | 
			
		||||
	buildId
 | 
			
		||||
}: {
 | 
			
		||||
	repository: string;
 | 
			
		||||
	buildId: string;
 | 
			
		||||
}): Promise<{ workdir: string; repodir: string }> => {
 | 
			
		||||
	const repodir = `/tmp/build-sources/${repository}/`;
 | 
			
		||||
	const workdir = `/tmp/build-sources/${repository}/${buildId}`;
 | 
			
		||||
 | 
			
		||||
@@ -148,20 +165,10 @@ export const createDirectories = async ({ repository, buildId }) => {
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function generateTimestamp() {
 | 
			
		||||
export function generateTimestamp(): string {
 | 
			
		||||
	return `${dayjs().format('HH:mm:ss.SSS')} `;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getDomain(domain) {
 | 
			
		||||
export function getDomain(domain: string): string {
 | 
			
		||||
	return domain?.replace('https://', '').replace('http://', '');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function dashify(str: string, options?: any): string {
 | 
			
		||||
	if (typeof str !== 'string') return str;
 | 
			
		||||
	return str
 | 
			
		||||
		.trim()
 | 
			
		||||
		.replace(/\W/g, (m) => (/[À-ž]/.test(m) ? m : '-'))
 | 
			
		||||
		.replace(/^-+|-+$/g, '')
 | 
			
		||||
		.replace(/-{2,}/g, (m) => (options && options.condense ? '-' : m))
 | 
			
		||||
		.toLowerCase();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,13 @@
 | 
			
		||||
import crypto from 'crypto';
 | 
			
		||||
const algorithm = 'aes-256-ctr';
 | 
			
		||||
 | 
			
		||||
export const base64Encode = (text: string) => {
 | 
			
		||||
export const base64Encode = (text: string): string => {
 | 
			
		||||
	return Buffer.from(text).toString('base64');
 | 
			
		||||
};
 | 
			
		||||
export const base64Decode = (text: string) => {
 | 
			
		||||
export const base64Decode = (text: string): string => {
 | 
			
		||||
	return Buffer.from(text, 'base64').toString('ascii');
 | 
			
		||||
};
 | 
			
		||||
export const encrypt = (text: string) => {
 | 
			
		||||
export const encrypt = (text: string): string => {
 | 
			
		||||
	if (text) {
 | 
			
		||||
		const iv = crypto.randomBytes(16);
 | 
			
		||||
		const cipher = crypto.createCipheriv(algorithm, process.env['COOLIFY_SECRET_KEY'], iv);
 | 
			
		||||
@@ -19,7 +19,7 @@ export const encrypt = (text: string) => {
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const decrypt = (hashString: string) => {
 | 
			
		||||
export const decrypt = (hashString: string): string => {
 | 
			
		||||
	if (hashString) {
 | 
			
		||||
		const hash: Hash = JSON.parse(hashString);
 | 
			
		||||
		const decipher = crypto.createDecipheriv(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,19 @@
 | 
			
		||||
import { decrypt, encrypt } from '$lib/crypto';
 | 
			
		||||
import { asyncExecShell, getEngine } from '$lib/common';
 | 
			
		||||
 | 
			
		||||
import { getDomain, removeDestinationDocker } from '$lib/common';
 | 
			
		||||
import { removeDestinationDocker } from '$lib/common';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
 | 
			
		||||
export async function listApplications(teamId) {
 | 
			
		||||
import type {
 | 
			
		||||
	DestinationDocker,
 | 
			
		||||
	GitSource,
 | 
			
		||||
	Secret,
 | 
			
		||||
	ApplicationSettings,
 | 
			
		||||
	Application,
 | 
			
		||||
	ApplicationPersistentStorage
 | 
			
		||||
} from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export async function listApplications(teamId: string): Promise<Application[]> {
 | 
			
		||||
	if (teamId === '0') {
 | 
			
		||||
		return await prisma.application.findMany({ include: { teams: true } });
 | 
			
		||||
	}
 | 
			
		||||
@@ -14,7 +23,13 @@ export async function listApplications(teamId) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function newApplication({ name, teamId }) {
 | 
			
		||||
export async function newApplication({
 | 
			
		||||
	name,
 | 
			
		||||
	teamId
 | 
			
		||||
}: {
 | 
			
		||||
	name: string;
 | 
			
		||||
	teamId: string;
 | 
			
		||||
}): Promise<Application> {
 | 
			
		||||
	return await prisma.application.create({
 | 
			
		||||
		data: {
 | 
			
		||||
			name,
 | 
			
		||||
@@ -24,34 +39,17 @@ export async function newApplication({ name, teamId }) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function importApplication({
 | 
			
		||||
	name,
 | 
			
		||||
	teamId,
 | 
			
		||||
	fqdn,
 | 
			
		||||
	port,
 | 
			
		||||
	buildCommand,
 | 
			
		||||
	startCommand,
 | 
			
		||||
	installCommand
 | 
			
		||||
}) {
 | 
			
		||||
	return await prisma.application.create({
 | 
			
		||||
		data: {
 | 
			
		||||
			name,
 | 
			
		||||
			fqdn,
 | 
			
		||||
			port,
 | 
			
		||||
			buildCommand,
 | 
			
		||||
			startCommand,
 | 
			
		||||
			installCommand,
 | 
			
		||||
			teams: { connect: { id: teamId } }
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function removeApplication({ id, teamId }) {
 | 
			
		||||
	const { fqdn, destinationDockerId, destinationDocker } = await prisma.application.findUnique({
 | 
			
		||||
export async function removeApplication({
 | 
			
		||||
	id,
 | 
			
		||||
	teamId
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	teamId: string;
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
	const { destinationDockerId, destinationDocker } = await prisma.application.findUnique({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		include: { destinationDocker: true }
 | 
			
		||||
	});
 | 
			
		||||
	const domain = getDomain(fqdn);
 | 
			
		||||
	if (destinationDockerId) {
 | 
			
		||||
		const host = getEngine(destinationDocker.engine);
 | 
			
		||||
		const { stdout: containers } = await asyncExecShell(
 | 
			
		||||
@@ -62,7 +60,6 @@ export async function removeApplication({ id, teamId }) {
 | 
			
		||||
			for (const container of containersArray) {
 | 
			
		||||
				const containerObj = JSON.parse(container);
 | 
			
		||||
				const id = containerObj.ID;
 | 
			
		||||
				const preview = containerObj.Image.split('-')[1];
 | 
			
		||||
				await removeDestinationDocker({ id, engine: destinationDocker.engine });
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -80,9 +77,23 @@ export async function removeApplication({ id, teamId }) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getApplicationWebhook({ projectId, branch }) {
 | 
			
		||||
export async function getApplicationWebhook({
 | 
			
		||||
	projectId,
 | 
			
		||||
	branch
 | 
			
		||||
}: {
 | 
			
		||||
	projectId: number;
 | 
			
		||||
	branch: string;
 | 
			
		||||
}): Promise<
 | 
			
		||||
	Application & {
 | 
			
		||||
		destinationDocker: DestinationDocker;
 | 
			
		||||
		settings: ApplicationSettings;
 | 
			
		||||
		gitSource: GitSource;
 | 
			
		||||
		secrets: Secret[];
 | 
			
		||||
		persistentStorage: ApplicationPersistentStorage[];
 | 
			
		||||
	}
 | 
			
		||||
> {
 | 
			
		||||
	try {
 | 
			
		||||
		let application = await prisma.application.findFirst({
 | 
			
		||||
		const application = await prisma.application.findFirst({
 | 
			
		||||
			where: { projectId, branch, settings: { autodeploy: true } },
 | 
			
		||||
			include: {
 | 
			
		||||
				destinationDocker: true,
 | 
			
		||||
@@ -131,16 +142,17 @@ export async function getApplicationWebhook({ projectId, branch }) {
 | 
			
		||||
		throw { status: 404, body: { message: e.message } };
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
export async function getApplicationById({ id }) {
 | 
			
		||||
	const body = await prisma.application.findFirst({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		include: { destinationDocker: true }
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	return { ...body };
 | 
			
		||||
}
 | 
			
		||||
export async function getApplication({ id, teamId }) {
 | 
			
		||||
	let body = {};
 | 
			
		||||
export async function getApplication({ id, teamId }: { id: string; teamId: string }): Promise<
 | 
			
		||||
	Application & {
 | 
			
		||||
		destinationDocker: DestinationDocker;
 | 
			
		||||
		settings: ApplicationSettings;
 | 
			
		||||
		gitSource: GitSource;
 | 
			
		||||
		secrets: Secret[];
 | 
			
		||||
		persistentStorage: ApplicationPersistentStorage[];
 | 
			
		||||
	}
 | 
			
		||||
> {
 | 
			
		||||
	let body;
 | 
			
		||||
	if (teamId === '0') {
 | 
			
		||||
		body = await prisma.application.findFirst({
 | 
			
		||||
			where: { id },
 | 
			
		||||
@@ -194,7 +206,14 @@ export async function configureGitRepository({
 | 
			
		||||
	projectId,
 | 
			
		||||
	webhookToken,
 | 
			
		||||
	autodeploy
 | 
			
		||||
}) {
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	repository: string;
 | 
			
		||||
	branch: string;
 | 
			
		||||
	projectId: number;
 | 
			
		||||
	webhookToken: string;
 | 
			
		||||
	autodeploy: boolean;
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
	if (webhookToken) {
 | 
			
		||||
		const encryptedWebhookToken = encrypt(webhookToken);
 | 
			
		||||
		await prisma.application.update({
 | 
			
		||||
@@ -224,7 +243,10 @@ export async function configureGitRepository({
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function configureBuildPack({ id, buildPack }) {
 | 
			
		||||
export async function configureBuildPack({
 | 
			
		||||
	id,
 | 
			
		||||
	buildPack
 | 
			
		||||
}: Pick<Application, 'id' | 'buildPack'>): Promise<Application> {
 | 
			
		||||
	return await prisma.application.update({ where: { id }, data: { buildPack } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -242,7 +264,21 @@ export async function configureApplication({
 | 
			
		||||
	pythonWSGI,
 | 
			
		||||
	pythonModule,
 | 
			
		||||
	pythonVariable
 | 
			
		||||
}) {
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	buildPack: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	port: number;
 | 
			
		||||
	installCommand: string;
 | 
			
		||||
	buildCommand: string;
 | 
			
		||||
	startCommand: string;
 | 
			
		||||
	baseDirectory: string;
 | 
			
		||||
	publishDirectory: string;
 | 
			
		||||
	pythonWSGI: string;
 | 
			
		||||
	pythonModule: string;
 | 
			
		||||
	pythonVariable: string;
 | 
			
		||||
}): Promise<Application> {
 | 
			
		||||
	return await prisma.application.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: {
 | 
			
		||||
@@ -262,11 +298,24 @@ export async function configureApplication({
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function checkDoubleBranch(branch, projectId) {
 | 
			
		||||
export async function checkDoubleBranch(branch: string, projectId: number): Promise<boolean> {
 | 
			
		||||
	const applications = await prisma.application.findMany({ where: { branch, projectId } });
 | 
			
		||||
	return applications.length > 1;
 | 
			
		||||
}
 | 
			
		||||
export async function setApplicationSettings({ id, debug, previews, dualCerts, autodeploy }) {
 | 
			
		||||
 | 
			
		||||
export async function setApplicationSettings({
 | 
			
		||||
	id,
 | 
			
		||||
	debug,
 | 
			
		||||
	previews,
 | 
			
		||||
	dualCerts,
 | 
			
		||||
	autodeploy
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	debug: boolean;
 | 
			
		||||
	previews: boolean;
 | 
			
		||||
	dualCerts: boolean;
 | 
			
		||||
	autodeploy: boolean;
 | 
			
		||||
}): Promise<Application & { destinationDocker: DestinationDocker }> {
 | 
			
		||||
	return await prisma.application.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { settings: { update: { debug, previews, dualCerts, autodeploy } } },
 | 
			
		||||
@@ -274,29 +323,6 @@ export async function setApplicationSettings({ id, debug, previews, dualCerts, a
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function createBuild({
 | 
			
		||||
	id,
 | 
			
		||||
	applicationId,
 | 
			
		||||
	destinationDockerId,
 | 
			
		||||
	gitSourceId,
 | 
			
		||||
	githubAppId,
 | 
			
		||||
	gitlabAppId,
 | 
			
		||||
	type
 | 
			
		||||
}) {
 | 
			
		||||
	return await prisma.build.create({
 | 
			
		||||
		data: {
 | 
			
		||||
			id,
 | 
			
		||||
			applicationId,
 | 
			
		||||
			destinationDockerId,
 | 
			
		||||
			gitSourceId,
 | 
			
		||||
			githubAppId,
 | 
			
		||||
			gitlabAppId,
 | 
			
		||||
			status: 'running',
 | 
			
		||||
			type
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getPersistentStorage(id) {
 | 
			
		||||
export async function getPersistentStorage(id: string): Promise<ApplicationPersistentStorage[]> {
 | 
			
		||||
	return await prisma.applicationPersistentStorage.findMany({ where: { applicationId: id } });
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,16 @@
 | 
			
		||||
import { getDomain } from '$lib/common';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
import type { Application, ServiceSecret, DestinationDocker, Secret } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export async function isBranchAlreadyUsed({ repository, branch, id }) {
 | 
			
		||||
export async function isBranchAlreadyUsed({
 | 
			
		||||
	repository,
 | 
			
		||||
	branch,
 | 
			
		||||
	id
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	repository: string;
 | 
			
		||||
	branch: string;
 | 
			
		||||
}): Promise<Application> {
 | 
			
		||||
	const application = await prisma.application.findUnique({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		include: { gitSource: true }
 | 
			
		||||
@@ -11,18 +20,42 @@ export async function isBranchAlreadyUsed({ repository, branch, id }) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function isDockerNetworkExists({ network }) {
 | 
			
		||||
export async function isDockerNetworkExists({
 | 
			
		||||
	network
 | 
			
		||||
}: {
 | 
			
		||||
	network: string;
 | 
			
		||||
}): Promise<DestinationDocker> {
 | 
			
		||||
	return await prisma.destinationDocker.findFirst({ where: { network } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function isServiceSecretExists({ id, name }) {
 | 
			
		||||
export async function isServiceSecretExists({
 | 
			
		||||
	id,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
}): Promise<ServiceSecret> {
 | 
			
		||||
	return await prisma.serviceSecret.findFirst({ where: { name, serviceId: id } });
 | 
			
		||||
}
 | 
			
		||||
export async function isSecretExists({ id, name, isPRMRSecret }) {
 | 
			
		||||
export async function isSecretExists({
 | 
			
		||||
	id,
 | 
			
		||||
	name,
 | 
			
		||||
	isPRMRSecret
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	isPRMRSecret: boolean;
 | 
			
		||||
}): Promise<Secret> {
 | 
			
		||||
	return await prisma.secret.findFirst({ where: { name, applicationId: id, isPRMRSecret } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function isDomainConfigured({ id, fqdn }) {
 | 
			
		||||
export async function isDomainConfigured({
 | 
			
		||||
	id,
 | 
			
		||||
	fqdn
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
}): Promise<boolean> {
 | 
			
		||||
	const domain = getDomain(fqdn);
 | 
			
		||||
	const nakedDomain = domain.replace('www.', '');
 | 
			
		||||
	const foundApp = await prisma.application.findFirst({
 | 
			
		||||
@@ -55,6 +88,5 @@ export async function isDomainConfigured({ id, fqdn }) {
 | 
			
		||||
		},
 | 
			
		||||
		select: { fqdn: true }
 | 
			
		||||
	});
 | 
			
		||||
	if (foundApp || foundService || coolifyFqdn) return true;
 | 
			
		||||
	return false;
 | 
			
		||||
	return !!(foundApp || foundService || coolifyFqdn);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,11 +6,11 @@ import {
 | 
			
		||||
} from '$lib/components/common';
 | 
			
		||||
import * as Prisma from '@prisma/client';
 | 
			
		||||
import { default as ProdPrisma } from '@prisma/client';
 | 
			
		||||
import type { PrismaClientOptions } from '@prisma/client/runtime';
 | 
			
		||||
import type { Database, DatabaseSettings } from '@prisma/client';
 | 
			
		||||
import generator from 'generate-password';
 | 
			
		||||
import forge from 'node-forge';
 | 
			
		||||
 | 
			
		||||
export function generatePassword(length = 24) {
 | 
			
		||||
export function generatePassword(length = 24): string {
 | 
			
		||||
	return generator.generate({
 | 
			
		||||
		length,
 | 
			
		||||
		numbers: true,
 | 
			
		||||
@@ -30,8 +30,14 @@ export const prisma = new PrismaClient({
 | 
			
		||||
	rejectOnNotFound: false
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export function ErrorHandler(e) {
 | 
			
		||||
	if (e! instanceof Error) {
 | 
			
		||||
export function ErrorHandler(e: {
 | 
			
		||||
	stdout?;
 | 
			
		||||
	message?: string;
 | 
			
		||||
	status?: number;
 | 
			
		||||
	name?: string;
 | 
			
		||||
	error?: string;
 | 
			
		||||
}): { status: number; body: { message: string; error: string } } {
 | 
			
		||||
	if (e && e instanceof Error) {
 | 
			
		||||
		e = new Error(e.toString());
 | 
			
		||||
	}
 | 
			
		||||
	let truncatedError = e;
 | 
			
		||||
@@ -39,8 +45,7 @@ export function ErrorHandler(e) {
 | 
			
		||||
		truncatedError = e.stdout;
 | 
			
		||||
	}
 | 
			
		||||
	if (e.message?.includes('docker run')) {
 | 
			
		||||
		let truncatedArray = [];
 | 
			
		||||
		truncatedArray = truncatedError.message.split('-').filter((line) => {
 | 
			
		||||
		const truncatedArray: string[] = truncatedError.message.split('-').filter((line) => {
 | 
			
		||||
			if (!line.startsWith('e ')) {
 | 
			
		||||
				return line;
 | 
			
		||||
			}
 | 
			
		||||
@@ -68,11 +73,11 @@ export function ErrorHandler(e) {
 | 
			
		||||
			payload.body.message = 'Already exists. Choose another name.';
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// console.error(e)
 | 
			
		||||
	return payload;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function generateSshKeyPair(): Promise<{ publicKey: string; privateKey: string }> {
 | 
			
		||||
	return await new Promise(async (resolve, reject) => {
 | 
			
		||||
	return await new Promise((resolve, reject) => {
 | 
			
		||||
		forge.pki.rsa.generateKeyPair({ bits: 4096, workers: -1 }, function (err, keys) {
 | 
			
		||||
			if (keys) {
 | 
			
		||||
				resolve({
 | 
			
		||||
@@ -86,35 +91,93 @@ export async function generateSshKeyPair(): Promise<{ publicKey: string; private
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getVersions(type) {
 | 
			
		||||
export function getVersions(type: string): string[] {
 | 
			
		||||
	const found = supportedDatabaseTypesAndVersions.find((t) => t.name === type);
 | 
			
		||||
	if (found) {
 | 
			
		||||
		return found.versions;
 | 
			
		||||
	}
 | 
			
		||||
	return [];
 | 
			
		||||
}
 | 
			
		||||
export function getDatabaseImage(type) {
 | 
			
		||||
 | 
			
		||||
export function getDatabaseImage(type: string): string {
 | 
			
		||||
	const found = supportedDatabaseTypesAndVersions.find((t) => t.name === type);
 | 
			
		||||
	if (found) {
 | 
			
		||||
		return found.baseImage;
 | 
			
		||||
	}
 | 
			
		||||
	return '';
 | 
			
		||||
}
 | 
			
		||||
export function getServiceImage(type) {
 | 
			
		||||
 | 
			
		||||
export function getServiceImage(type: string): string {
 | 
			
		||||
	const found = supportedServiceTypesAndVersions.find((t) => t.name === type);
 | 
			
		||||
	if (found) {
 | 
			
		||||
		return found.baseImage;
 | 
			
		||||
	}
 | 
			
		||||
	return '';
 | 
			
		||||
}
 | 
			
		||||
export function getServiceImages(type) {
 | 
			
		||||
 | 
			
		||||
export function getServiceImages(type: string): string[] {
 | 
			
		||||
	const found = supportedServiceTypesAndVersions.find((t) => t.name === type);
 | 
			
		||||
	if (found) {
 | 
			
		||||
		return found.images;
 | 
			
		||||
	}
 | 
			
		||||
	return [];
 | 
			
		||||
}
 | 
			
		||||
export function generateDatabaseConfiguration(database) {
 | 
			
		||||
 | 
			
		||||
export function generateDatabaseConfiguration(database: Database & { settings: DatabaseSettings }):
 | 
			
		||||
	| {
 | 
			
		||||
			volume: string;
 | 
			
		||||
			image: string;
 | 
			
		||||
			ulimits: Record<string, unknown>;
 | 
			
		||||
			privatePort: number;
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				MYSQL_DATABASE: string;
 | 
			
		||||
				MYSQL_PASSWORD: string;
 | 
			
		||||
				MYSQL_ROOT_USER: string;
 | 
			
		||||
				MYSQL_USER: string;
 | 
			
		||||
				MYSQL_ROOT_PASSWORD: string;
 | 
			
		||||
			};
 | 
			
		||||
	  }
 | 
			
		||||
	| {
 | 
			
		||||
			volume: string;
 | 
			
		||||
			image: string;
 | 
			
		||||
			ulimits: Record<string, unknown>;
 | 
			
		||||
			privatePort: number;
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				MONGODB_ROOT_USER: string;
 | 
			
		||||
				MONGODB_ROOT_PASSWORD: string;
 | 
			
		||||
			};
 | 
			
		||||
	  }
 | 
			
		||||
	| {
 | 
			
		||||
			volume: string;
 | 
			
		||||
			image: string;
 | 
			
		||||
			ulimits: Record<string, unknown>;
 | 
			
		||||
			privatePort: number;
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				POSTGRESQL_USERNAME: string;
 | 
			
		||||
				POSTGRESQL_PASSWORD: string;
 | 
			
		||||
				POSTGRESQL_DATABASE: string;
 | 
			
		||||
			};
 | 
			
		||||
	  }
 | 
			
		||||
	| {
 | 
			
		||||
			volume: string;
 | 
			
		||||
			image: string;
 | 
			
		||||
			ulimits: Record<string, unknown>;
 | 
			
		||||
			privatePort: number;
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				REDIS_AOF_ENABLED: string;
 | 
			
		||||
				REDIS_PASSWORD: string;
 | 
			
		||||
			};
 | 
			
		||||
	  }
 | 
			
		||||
	| {
 | 
			
		||||
			volume: string;
 | 
			
		||||
			image: string;
 | 
			
		||||
			ulimits: Record<string, unknown>;
 | 
			
		||||
			privatePort: number;
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				COUCHDB_PASSWORD: string;
 | 
			
		||||
				COUCHDB_USER: string;
 | 
			
		||||
			};
 | 
			
		||||
	  } {
 | 
			
		||||
	const {
 | 
			
		||||
		id,
 | 
			
		||||
		dbUser,
 | 
			
		||||
@@ -129,7 +192,6 @@ export function generateDatabaseConfiguration(database) {
 | 
			
		||||
	const baseImage = getDatabaseImage(type);
 | 
			
		||||
	if (type === 'mysql') {
 | 
			
		||||
		return {
 | 
			
		||||
			// url: `mysql://${dbUser}:${dbUserPassword}@${id}:${isPublic ? port : 3306}/${defaultDatabase}`,
 | 
			
		||||
			privatePort: 3306,
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				MYSQL_USER: dbUser,
 | 
			
		||||
@@ -144,7 +206,6 @@ export function generateDatabaseConfiguration(database) {
 | 
			
		||||
		};
 | 
			
		||||
	} else if (type === 'mongodb') {
 | 
			
		||||
		return {
 | 
			
		||||
			// url: `mongodb://${dbUser}:${dbUserPassword}@${id}:${isPublic ? port : 27017}/${defaultDatabase}`,
 | 
			
		||||
			privatePort: 27017,
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				MONGODB_ROOT_USER: rootUser,
 | 
			
		||||
@@ -156,7 +217,6 @@ export function generateDatabaseConfiguration(database) {
 | 
			
		||||
		};
 | 
			
		||||
	} else if (type === 'postgresql') {
 | 
			
		||||
		return {
 | 
			
		||||
			// url: `psql://${dbUser}:${dbUserPassword}@${id}:${isPublic ? port : 5432}/${defaultDatabase}`,
 | 
			
		||||
			privatePort: 5432,
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				POSTGRESQL_POSTGRES_PASSWORD: rootUserPassword,
 | 
			
		||||
@@ -170,7 +230,6 @@ export function generateDatabaseConfiguration(database) {
 | 
			
		||||
		};
 | 
			
		||||
	} else if (type === 'redis') {
 | 
			
		||||
		return {
 | 
			
		||||
			// url: `redis://${dbUser}:${dbUserPassword}@${id}:${isPublic ? port : 6379}/${defaultDatabase}`,
 | 
			
		||||
			privatePort: 6379,
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				REDIS_PASSWORD: dbUserPassword,
 | 
			
		||||
@@ -182,7 +241,6 @@ export function generateDatabaseConfiguration(database) {
 | 
			
		||||
		};
 | 
			
		||||
	} else if (type === 'couchdb') {
 | 
			
		||||
		return {
 | 
			
		||||
			// url: `couchdb://${dbUser}:${dbUserPassword}@${id}:${isPublic ? port : 5984}/${defaultDatabase}`,
 | 
			
		||||
			privatePort: 5984,
 | 
			
		||||
			environmentVariables: {
 | 
			
		||||
				COUCHDB_PASSWORD: dbUserPassword,
 | 
			
		||||
@@ -193,18 +251,4 @@ export function generateDatabaseConfiguration(database) {
 | 
			
		||||
			ulimits: {}
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
	// } else if (type === 'clickhouse') {
 | 
			
		||||
	//     return {
 | 
			
		||||
	//         url: `clickhouse://${dbUser}:${dbUserPassword}@${id}:${port}/${defaultDatabase}`,
 | 
			
		||||
	//         privatePort: 9000,
 | 
			
		||||
	//         image: `bitnami/clickhouse-server:${version}`,
 | 
			
		||||
	//         volume: `${id}-${type}-data:/var/lib/clickhouse`,
 | 
			
		||||
	//         ulimits: {
 | 
			
		||||
	// 			nofile: {
 | 
			
		||||
	// 				soft: 262144,
 | 
			
		||||
	// 				hard: 262144
 | 
			
		||||
	// 			}
 | 
			
		||||
	// 		}
 | 
			
		||||
	//     }
 | 
			
		||||
	// }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,11 @@
 | 
			
		||||
import { decrypt, encrypt } from '$lib/crypto';
 | 
			
		||||
import * as db from '$lib/database';
 | 
			
		||||
import cuid from 'cuid';
 | 
			
		||||
import { generatePassword } from '.';
 | 
			
		||||
import { prisma, ErrorHandler } from './common';
 | 
			
		||||
import getPort, { portNumbers } from 'get-port';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
import { asyncExecShell, getEngine, removeContainer } from '$lib/common';
 | 
			
		||||
import type { Database, DatabaseSettings, DestinationDocker } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export async function listDatabases(teamId) {
 | 
			
		||||
export async function listDatabases(teamId: string): Promise<Database[]> {
 | 
			
		||||
	if (teamId === '0') {
 | 
			
		||||
		return await prisma.database.findMany({ include: { teams: true } });
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -16,7 +15,14 @@ export async function listDatabases(teamId) {
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
export async function newDatabase({ name, teamId }) {
 | 
			
		||||
 | 
			
		||||
export async function newDatabase({
 | 
			
		||||
	name,
 | 
			
		||||
	teamId
 | 
			
		||||
}: {
 | 
			
		||||
	name: string;
 | 
			
		||||
	teamId: string;
 | 
			
		||||
}): Promise<Database> {
 | 
			
		||||
	const dbUser = cuid();
 | 
			
		||||
	const dbUserPassword = encrypt(generatePassword());
 | 
			
		||||
	const rootUser = cuid();
 | 
			
		||||
@@ -37,8 +43,14 @@ export async function newDatabase({ name, teamId }) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getDatabase({ id, teamId }) {
 | 
			
		||||
	let body = {};
 | 
			
		||||
export async function getDatabase({
 | 
			
		||||
	id,
 | 
			
		||||
	teamId
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	teamId: string;
 | 
			
		||||
}): Promise<Database & { destinationDocker: DestinationDocker; settings: DatabaseSettings }> {
 | 
			
		||||
	let body;
 | 
			
		||||
	if (teamId === '0') {
 | 
			
		||||
		body = await prisma.database.findFirst({
 | 
			
		||||
			where: { id },
 | 
			
		||||
@@ -50,20 +62,25 @@ export async function getDatabase({ id, teamId }) {
 | 
			
		||||
			include: { destinationDocker: true, settings: true }
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (body.dbUserPassword) body.dbUserPassword = decrypt(body.dbUserPassword);
 | 
			
		||||
	if (body.rootUserPassword) body.rootUserPassword = decrypt(body.rootUserPassword);
 | 
			
		||||
 | 
			
		||||
	return { ...body };
 | 
			
		||||
	return body;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function removeDatabase({ id }) {
 | 
			
		||||
export async function removeDatabase({ id }: { id: string }): Promise<void> {
 | 
			
		||||
	await prisma.databaseSettings.deleteMany({ where: { databaseId: id } });
 | 
			
		||||
	await prisma.database.delete({ where: { id } });
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function configureDatabaseType({ id, type }) {
 | 
			
		||||
export async function configureDatabaseType({
 | 
			
		||||
	id,
 | 
			
		||||
	type
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	type: string;
 | 
			
		||||
}): Promise<Database> {
 | 
			
		||||
	return await prisma.database.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { type }
 | 
			
		||||
@@ -79,7 +96,7 @@ export async function setDatabase({
 | 
			
		||||
	version?: string;
 | 
			
		||||
	isPublic?: boolean;
 | 
			
		||||
	appendOnly?: boolean;
 | 
			
		||||
}) {
 | 
			
		||||
}): Promise<Database> {
 | 
			
		||||
	return await prisma.database.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: {
 | 
			
		||||
@@ -97,7 +114,16 @@ export async function updateDatabase({
 | 
			
		||||
	rootUser,
 | 
			
		||||
	rootUserPassword,
 | 
			
		||||
	version
 | 
			
		||||
}) {
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	defaultDatabase: string;
 | 
			
		||||
	dbUser: string;
 | 
			
		||||
	dbUserPassword: string;
 | 
			
		||||
	rootUser: string;
 | 
			
		||||
	rootUserPassword: string;
 | 
			
		||||
	version: string;
 | 
			
		||||
}): Promise<Database> {
 | 
			
		||||
	const encryptedDbUserPassword = dbUserPassword && encrypt(dbUserPassword);
 | 
			
		||||
	const encryptedRootUserPassword = rootUserPassword && encrypt(rootUserPassword);
 | 
			
		||||
	return await prisma.database.update({
 | 
			
		||||
@@ -114,7 +140,9 @@ export async function updateDatabase({
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function stopDatabase(database) {
 | 
			
		||||
export async function stopDatabase(
 | 
			
		||||
	database: Database & { destinationDocker: DestinationDocker }
 | 
			
		||||
): Promise<boolean> {
 | 
			
		||||
	let everStarted = false;
 | 
			
		||||
	const {
 | 
			
		||||
		id,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,22 @@
 | 
			
		||||
import { asyncExecShell, getEngine } from '$lib/common';
 | 
			
		||||
import { decrypt, encrypt } from '$lib/crypto';
 | 
			
		||||
import { dockerInstance } from '$lib/docker';
 | 
			
		||||
import { startCoolifyProxy } from '$lib/haproxy';
 | 
			
		||||
import { getDatabaseImage } from '.';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
import type { DestinationDocker, Service, Application, Prisma } from '@prisma/client';
 | 
			
		||||
import type { CreateDockerDestination } from '$lib/types/destinations';
 | 
			
		||||
 | 
			
		||||
export async function listDestinations(teamId) {
 | 
			
		||||
type DestinationConfigurationObject = {
 | 
			
		||||
	id: string;
 | 
			
		||||
	destinationId: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type FindDestinationFromTeam = {
 | 
			
		||||
	id: string;
 | 
			
		||||
	teamId: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export async function listDestinations(teamId: string): Promise<DestinationDocker[]> {
 | 
			
		||||
	if (teamId === '0') {
 | 
			
		||||
		return await prisma.destinationDocker.findMany({ include: { teams: true } });
 | 
			
		||||
	}
 | 
			
		||||
@@ -15,19 +26,28 @@ export async function listDestinations(teamId) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function configureDestinationForService({ id, destinationId }) {
 | 
			
		||||
export async function configureDestinationForService({
 | 
			
		||||
	id,
 | 
			
		||||
	destinationId
 | 
			
		||||
}: DestinationConfigurationObject): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { destinationDocker: { connect: { id: destinationId } } }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
export async function configureDestinationForApplication({ id, destinationId }) {
 | 
			
		||||
export async function configureDestinationForApplication({
 | 
			
		||||
	id,
 | 
			
		||||
	destinationId
 | 
			
		||||
}: DestinationConfigurationObject): Promise<Application> {
 | 
			
		||||
	return await prisma.application.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { destinationDocker: { connect: { id: destinationId } } }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
export async function configureDestinationForDatabase({ id, destinationId }) {
 | 
			
		||||
export async function configureDestinationForDatabase({
 | 
			
		||||
	id,
 | 
			
		||||
	destinationId
 | 
			
		||||
}: DestinationConfigurationObject): Promise<void> {
 | 
			
		||||
	await prisma.database.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { destinationDocker: { connect: { id: destinationId } } }
 | 
			
		||||
@@ -48,7 +68,12 @@ export async function configureDestinationForDatabase({ id, destinationId }) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
export async function updateDestination({ id, name, engine, network }) {
 | 
			
		||||
export async function updateDestination({
 | 
			
		||||
	id,
 | 
			
		||||
	name,
 | 
			
		||||
	engine,
 | 
			
		||||
	network
 | 
			
		||||
}: Pick<DestinationDocker, 'id' | 'name' | 'engine' | 'network'>): Promise<DestinationDocker> {
 | 
			
		||||
	return await prisma.destinationDocker.update({ where: { id }, data: { name, engine, network } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -58,13 +83,8 @@ export async function newRemoteDestination({
 | 
			
		||||
	engine,
 | 
			
		||||
	network,
 | 
			
		||||
	isCoolifyProxyUsed,
 | 
			
		||||
	remoteEngine,
 | 
			
		||||
	ipAddress,
 | 
			
		||||
	user,
 | 
			
		||||
	port,
 | 
			
		||||
	sshPrivateKey
 | 
			
		||||
}) {
 | 
			
		||||
	const encryptedPrivateKey = encrypt(sshPrivateKey);
 | 
			
		||||
	remoteEngine
 | 
			
		||||
}: CreateDockerDestination): Promise<string> {
 | 
			
		||||
	const destination = await prisma.destinationDocker.create({
 | 
			
		||||
		data: {
 | 
			
		||||
			name,
 | 
			
		||||
@@ -72,16 +92,18 @@ export async function newRemoteDestination({
 | 
			
		||||
			engine,
 | 
			
		||||
			network,
 | 
			
		||||
			isCoolifyProxyUsed,
 | 
			
		||||
			remoteEngine,
 | 
			
		||||
			ipAddress,
 | 
			
		||||
			user,
 | 
			
		||||
			port,
 | 
			
		||||
			sshPrivateKey: encryptedPrivateKey
 | 
			
		||||
			remoteEngine
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	return destination.id;
 | 
			
		||||
}
 | 
			
		||||
export async function newLocalDestination({ name, teamId, engine, network, isCoolifyProxyUsed }) {
 | 
			
		||||
export async function newLocalDestination({
 | 
			
		||||
	name,
 | 
			
		||||
	teamId,
 | 
			
		||||
	engine,
 | 
			
		||||
	network,
 | 
			
		||||
	isCoolifyProxyUsed
 | 
			
		||||
}: CreateDockerDestination): Promise<string> {
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
	const docker = dockerInstance({ destinationDocker: { engine, network } });
 | 
			
		||||
	const found = await docker.engine.listNetworks({ filters: { name: [`^${network}$`] } });
 | 
			
		||||
@@ -99,18 +121,14 @@ export async function newLocalDestination({ name, teamId, engine, network, isCoo
 | 
			
		||||
			(destination) => destination.network !== network && destination.isCoolifyProxyUsed === true
 | 
			
		||||
		);
 | 
			
		||||
		if (proxyConfigured) {
 | 
			
		||||
			if (proxyConfigured.isCoolifyProxyUsed) {
 | 
			
		||||
				isCoolifyProxyUsed = true;
 | 
			
		||||
			} else {
 | 
			
		||||
				isCoolifyProxyUsed = false;
 | 
			
		||||
			}
 | 
			
		||||
			isCoolifyProxyUsed = !!proxyConfigured.isCoolifyProxyUsed;
 | 
			
		||||
		}
 | 
			
		||||
		await prisma.destinationDocker.updateMany({ where: { engine }, data: { isCoolifyProxyUsed } });
 | 
			
		||||
	}
 | 
			
		||||
	if (isCoolifyProxyUsed) await startCoolifyProxy(engine);
 | 
			
		||||
	return destination.id;
 | 
			
		||||
}
 | 
			
		||||
export async function removeDestination({ id }) {
 | 
			
		||||
export async function removeDestination({ id }: Pick<DestinationDocker, 'id'>): Promise<void> {
 | 
			
		||||
	const destination = await prisma.destinationDocker.delete({ where: { id } });
 | 
			
		||||
	if (destination.isCoolifyProxyUsed) {
 | 
			
		||||
		const host = getEngine(destination.engine);
 | 
			
		||||
@@ -127,8 +145,11 @@ export async function removeDestination({ id }) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getDestination({ id, teamId }) {
 | 
			
		||||
	let destination = {};
 | 
			
		||||
export async function getDestination({
 | 
			
		||||
	id,
 | 
			
		||||
	teamId
 | 
			
		||||
}: FindDestinationFromTeam): Promise<DestinationDocker & { sshPrivateKey?: string }> {
 | 
			
		||||
	let destination;
 | 
			
		||||
	if (teamId === '0') {
 | 
			
		||||
		destination = await prisma.destinationDocker.findFirst({
 | 
			
		||||
			where: { id }
 | 
			
		||||
@@ -141,13 +162,22 @@ export async function getDestination({ id, teamId }) {
 | 
			
		||||
 | 
			
		||||
	return destination;
 | 
			
		||||
}
 | 
			
		||||
export async function getDestinationByApplicationId({ id, teamId }) {
 | 
			
		||||
export async function getDestinationByApplicationId({
 | 
			
		||||
	id,
 | 
			
		||||
	teamId
 | 
			
		||||
}: FindDestinationFromTeam): Promise<DestinationDocker> {
 | 
			
		||||
	return await prisma.destinationDocker.findFirst({
 | 
			
		||||
		where: { application: { some: { id } }, teams: { some: { id: teamId } } }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function setDestinationSettings({ engine, isCoolifyProxyUsed }) {
 | 
			
		||||
export async function setDestinationSettings({
 | 
			
		||||
	engine,
 | 
			
		||||
	isCoolifyProxyUsed
 | 
			
		||||
}: {
 | 
			
		||||
	engine: string;
 | 
			
		||||
	isCoolifyProxyUsed: boolean;
 | 
			
		||||
}): Promise<Prisma.BatchPayload> {
 | 
			
		||||
	return await prisma.destinationDocker.updateMany({
 | 
			
		||||
		where: { engine },
 | 
			
		||||
		data: { isCoolifyProxyUsed }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
import { decrypt, encrypt } from '$lib/crypto';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
import type { GithubApp, GitlabApp, GitSource, Prisma, Application } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export async function listSources(teamId) {
 | 
			
		||||
export async function listSources(
 | 
			
		||||
	teamId: string | Prisma.StringFilter
 | 
			
		||||
): Promise<(GitSource & { githubApp?: GithubApp; gitlabApp?: GitlabApp })[]> {
 | 
			
		||||
	if (teamId === '0') {
 | 
			
		||||
		return await prisma.gitSource.findMany({
 | 
			
		||||
			include: { githubApp: true, gitlabApp: true, teams: true }
 | 
			
		||||
@@ -13,7 +16,21 @@ export async function listSources(teamId) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function newSource({ teamId, name }) {
 | 
			
		||||
export async function newSource({
 | 
			
		||||
	name,
 | 
			
		||||
	teamId,
 | 
			
		||||
	type,
 | 
			
		||||
	htmlUrl,
 | 
			
		||||
	apiUrl,
 | 
			
		||||
	organization
 | 
			
		||||
}: {
 | 
			
		||||
	name: string;
 | 
			
		||||
	teamId: string;
 | 
			
		||||
	type: string;
 | 
			
		||||
	htmlUrl: string;
 | 
			
		||||
	apiUrl: string;
 | 
			
		||||
	organization: string;
 | 
			
		||||
}): Promise<GitSource> {
 | 
			
		||||
	return await prisma.gitSource.create({
 | 
			
		||||
		data: {
 | 
			
		||||
			name,
 | 
			
		||||
@@ -21,7 +38,7 @@ export async function newSource({ teamId, name }) {
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
export async function removeSource({ id }) {
 | 
			
		||||
export async function removeSource({ id }: { id: string }): Promise<void> {
 | 
			
		||||
	const source = await prisma.gitSource.delete({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		include: { githubApp: true, gitlabApp: true }
 | 
			
		||||
@@ -30,8 +47,14 @@ export async function removeSource({ id }) {
 | 
			
		||||
	if (source.gitlabAppId) await prisma.gitlabApp.delete({ where: { id: source.gitlabAppId } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getSource({ id, teamId }) {
 | 
			
		||||
	let body = {};
 | 
			
		||||
export async function getSource({
 | 
			
		||||
	id,
 | 
			
		||||
	teamId
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	teamId: string;
 | 
			
		||||
}): Promise<GitSource & { githubApp: GithubApp; gitlabApp: GitlabApp }> {
 | 
			
		||||
	let body;
 | 
			
		||||
	if (teamId === '0') {
 | 
			
		||||
		body = await prisma.gitSource.findFirst({
 | 
			
		||||
			where: { id },
 | 
			
		||||
@@ -80,19 +103,31 @@ export async function addGitLabSource({
 | 
			
		||||
			appId,
 | 
			
		||||
			oauthId,
 | 
			
		||||
			groupName,
 | 
			
		||||
			appSecret: encrptedAppSecret,
 | 
			
		||||
			appSecret: encryptedAppSecret,
 | 
			
		||||
			gitSource: { connect: { id } }
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function configureGitsource({ id, gitSourceId }) {
 | 
			
		||||
export async function configureGitsource({
 | 
			
		||||
	id,
 | 
			
		||||
	gitSourceId
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	gitSourceId: string;
 | 
			
		||||
}): Promise<Application> {
 | 
			
		||||
	return await prisma.application.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { gitSource: { connect: { id: gitSourceId } } }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
export async function updateGitsource({ id, name, htmlUrl, apiUrl }) {
 | 
			
		||||
export async function updateGitsource({
 | 
			
		||||
	id,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
}): Promise<GitSource> {
 | 
			
		||||
	return await prisma.gitSource.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { name, htmlUrl, apiUrl }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,15 @@
 | 
			
		||||
import { decrypt, encrypt } from '$lib/crypto';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
import type { GithubApp } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export async function addInstallation({ gitSourceId, installation_id }) {
 | 
			
		||||
// TODO: We should change installation_id to be camelCase
 | 
			
		||||
export async function addInstallation({
 | 
			
		||||
	gitSourceId,
 | 
			
		||||
	installation_id
 | 
			
		||||
}: {
 | 
			
		||||
	gitSourceId: string;
 | 
			
		||||
	installation_id: string;
 | 
			
		||||
}): Promise<GithubApp> {
 | 
			
		||||
	const source = await prisma.gitSource.findUnique({
 | 
			
		||||
		where: { id: gitSourceId },
 | 
			
		||||
		include: { githubApp: true }
 | 
			
		||||
@@ -12,8 +20,12 @@ export async function addInstallation({ gitSourceId, installation_id }) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getUniqueGithubApp({ githubAppId }) {
 | 
			
		||||
	let body = await prisma.githubApp.findUnique({ where: { id: githubAppId } });
 | 
			
		||||
export async function getUniqueGithubApp({
 | 
			
		||||
	githubAppId
 | 
			
		||||
}: {
 | 
			
		||||
	githubAppId: string;
 | 
			
		||||
}): Promise<GithubApp> {
 | 
			
		||||
	const body = await prisma.githubApp.findUnique({ where: { id: githubAppId } });
 | 
			
		||||
	if (body.privateKey) body.privateKey = decrypt(body.privateKey);
 | 
			
		||||
	return body;
 | 
			
		||||
}
 | 
			
		||||
@@ -26,7 +38,15 @@ export async function createGithubApp({
 | 
			
		||||
	pem,
 | 
			
		||||
	webhook_secret,
 | 
			
		||||
	state
 | 
			
		||||
}) {
 | 
			
		||||
}: {
 | 
			
		||||
	id: number;
 | 
			
		||||
	client_id: string;
 | 
			
		||||
	slug: string;
 | 
			
		||||
	client_secret: string;
 | 
			
		||||
	pem: string;
 | 
			
		||||
	webhook_secret: string;
 | 
			
		||||
	state: string;
 | 
			
		||||
}): Promise<GithubApp> {
 | 
			
		||||
	const encryptedClientSecret = encrypt(client_secret);
 | 
			
		||||
	const encryptedWebhookSecret = encrypt(webhook_secret);
 | 
			
		||||
	const encryptedPem = encrypt(pem);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,14 @@
 | 
			
		||||
import { encrypt } from '$lib/crypto';
 | 
			
		||||
import { generateSshKeyPair, prisma } from './common';
 | 
			
		||||
import type { GitlabApp } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export async function updateDeployKey({ id, deployKeyId }) {
 | 
			
		||||
export async function updateDeployKey({
 | 
			
		||||
	id,
 | 
			
		||||
	deployKeyId
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	deployKeyId: number;
 | 
			
		||||
}): Promise<GitlabApp> {
 | 
			
		||||
	const application = await prisma.application.findUnique({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		include: { gitSource: { include: { gitlabApp: true } } }
 | 
			
		||||
@@ -11,14 +18,24 @@ export async function updateDeployKey({ id, deployKeyId }) {
 | 
			
		||||
		data: { deployKeyId }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
export async function getSshKey({ id }) {
 | 
			
		||||
export async function getSshKey({
 | 
			
		||||
	id
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
}): Promise<{ status: number; body: { publicKey: string } }> {
 | 
			
		||||
	const application = await prisma.application.findUnique({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		include: { gitSource: { include: { gitlabApp: true } } }
 | 
			
		||||
	});
 | 
			
		||||
	return { status: 200, body: { publicKey: application.gitSource.gitlabApp.publicSshKey } };
 | 
			
		||||
}
 | 
			
		||||
export async function generateSshKey({ id }) {
 | 
			
		||||
export async function generateSshKey({
 | 
			
		||||
	id
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
}): Promise<
 | 
			
		||||
	{ status: number; body: { publicKey: string } } | { status: number; body?: undefined }
 | 
			
		||||
> {
 | 
			
		||||
	const application = await prisma.application.findUnique({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		include: { gitSource: { include: { gitlabApp: true } } }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,13 @@
 | 
			
		||||
import type { BuildLog } from '@prisma/client';
 | 
			
		||||
import { prisma, ErrorHandler } from './common';
 | 
			
		||||
 | 
			
		||||
export async function listLogs({ buildId, last = 0 }) {
 | 
			
		||||
export async function listLogs({
 | 
			
		||||
	buildId,
 | 
			
		||||
	last = 0
 | 
			
		||||
}: {
 | 
			
		||||
	buildId: string;
 | 
			
		||||
	last: number;
 | 
			
		||||
}): Promise<BuildLog[] | { status: number; body: { message: string; error: string } }> {
 | 
			
		||||
	try {
 | 
			
		||||
		const body = await prisma.buildLog.findMany({
 | 
			
		||||
			where: { buildId, time: { gt: last } },
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
import { encrypt, decrypt } from '$lib/crypto';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
import type { ServiceSecret, Secret, Prisma } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export async function listServiceSecrets(serviceId: string) {
 | 
			
		||||
export async function listServiceSecrets(serviceId: string): Promise<ServiceSecret[]> {
 | 
			
		||||
	let secrets = await prisma.serviceSecret.findMany({
 | 
			
		||||
		where: { serviceId },
 | 
			
		||||
		orderBy: { createdAt: 'desc' }
 | 
			
		||||
@@ -14,7 +15,7 @@ export async function listServiceSecrets(serviceId: string) {
 | 
			
		||||
	return secrets;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function listSecrets(applicationId: string) {
 | 
			
		||||
export async function listSecrets(applicationId: string): Promise<Secret[]> {
 | 
			
		||||
	let secrets = await prisma.secret.findMany({
 | 
			
		||||
		where: { applicationId },
 | 
			
		||||
		orderBy: { createdAt: 'desc' }
 | 
			
		||||
@@ -27,20 +28,48 @@ export async function listSecrets(applicationId: string) {
 | 
			
		||||
	return secrets;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function createServiceSecret({ id, name, value }) {
 | 
			
		||||
export async function createServiceSecret({
 | 
			
		||||
	id,
 | 
			
		||||
	name,
 | 
			
		||||
	value
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	value: string;
 | 
			
		||||
}): Promise<ServiceSecret> {
 | 
			
		||||
	value = encrypt(value);
 | 
			
		||||
	return await prisma.serviceSecret.create({
 | 
			
		||||
		data: { name, value, service: { connect: { id } } }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
export async function createSecret({ id, name, value, isBuildSecret, isPRMRSecret }) {
 | 
			
		||||
export async function createSecret({
 | 
			
		||||
	id,
 | 
			
		||||
	name,
 | 
			
		||||
	value,
 | 
			
		||||
	isBuildSecret,
 | 
			
		||||
	isPRMRSecret
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	value: string;
 | 
			
		||||
	isBuildSecret: boolean;
 | 
			
		||||
	isPRMRSecret: boolean;
 | 
			
		||||
}): Promise<Secret> {
 | 
			
		||||
	value = encrypt(value);
 | 
			
		||||
	return await prisma.secret.create({
 | 
			
		||||
		data: { name, value, isBuildSecret, isPRMRSecret, application: { connect: { id } } }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function updateServiceSecret({ id, name, value }) {
 | 
			
		||||
export async function updateServiceSecret({
 | 
			
		||||
	id,
 | 
			
		||||
	name,
 | 
			
		||||
	value
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	value: string;
 | 
			
		||||
}): Promise<Prisma.BatchPayload | ServiceSecret> {
 | 
			
		||||
	value = encrypt(value);
 | 
			
		||||
	const found = await prisma.serviceSecret.findFirst({ where: { serviceId: id, name } });
 | 
			
		||||
 | 
			
		||||
@@ -55,7 +84,19 @@ export async function updateServiceSecret({ id, name, value }) {
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
export async function updateSecret({ id, name, value, isBuildSecret, isPRMRSecret }) {
 | 
			
		||||
export async function updateSecret({
 | 
			
		||||
	id,
 | 
			
		||||
	name,
 | 
			
		||||
	value,
 | 
			
		||||
	isBuildSecret,
 | 
			
		||||
	isPRMRSecret
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	value: string;
 | 
			
		||||
	isBuildSecret: boolean;
 | 
			
		||||
	isPRMRSecret: boolean;
 | 
			
		||||
}): Promise<Prisma.BatchPayload | Secret> {
 | 
			
		||||
	value = encrypt(value);
 | 
			
		||||
	const found = await prisma.secret.findFirst({ where: { applicationId: id, name, isPRMRSecret } });
 | 
			
		||||
 | 
			
		||||
@@ -71,10 +112,22 @@ export async function updateSecret({ id, name, value, isBuildSecret, isPRMRSecre
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function removeServiceSecret({ id, name }) {
 | 
			
		||||
export async function removeServiceSecret({
 | 
			
		||||
	id,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
}): Promise<Prisma.BatchPayload> {
 | 
			
		||||
	return await prisma.serviceSecret.deleteMany({ where: { serviceId: id, name } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function removeSecret({ id, name }) {
 | 
			
		||||
export async function removeSecret({
 | 
			
		||||
	id,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
}): Promise<Prisma.BatchPayload> {
 | 
			
		||||
	return await prisma.secret.deleteMany({ where: { applicationId: id, name } });
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,10 @@
 | 
			
		||||
import { asyncExecShell, getEngine } from '$lib/common';
 | 
			
		||||
import { decrypt, encrypt } from '$lib/crypto';
 | 
			
		||||
import type { Minio, Service } from '@prisma/client';
 | 
			
		||||
import cuid from 'cuid';
 | 
			
		||||
import { generatePassword } from '.';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
 | 
			
		||||
export async function listServices(teamId) {
 | 
			
		||||
export async function listServices(teamId: string): Promise<Service[]> {
 | 
			
		||||
	if (teamId === '0') {
 | 
			
		||||
		return await prisma.service.findMany({ include: { teams: true } });
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -15,12 +15,18 @@ export async function listServices(teamId) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function newService({ name, teamId }) {
 | 
			
		||||
export async function newService({
 | 
			
		||||
	name,
 | 
			
		||||
	teamId
 | 
			
		||||
}: {
 | 
			
		||||
	name: string;
 | 
			
		||||
	teamId: string;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.create({ data: { name, teams: { connect: { id: teamId } } } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getService({ id, teamId }) {
 | 
			
		||||
	let body = {};
 | 
			
		||||
export async function getService({ id, teamId }: { id: string; teamId: string }): Promise<Service> {
 | 
			
		||||
	let body;
 | 
			
		||||
	const include = {
 | 
			
		||||
		destinationDocker: true,
 | 
			
		||||
		plausibleAnalytics: true,
 | 
			
		||||
@@ -83,7 +89,13 @@ export async function getService({ id, teamId }) {
 | 
			
		||||
	return { ...body, settings };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function configureServiceType({ id, type }) {
 | 
			
		||||
export async function configureServiceType({
 | 
			
		||||
	id,
 | 
			
		||||
	type
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	type: string;
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
	if (type === 'plausibleanalytics') {
 | 
			
		||||
		const password = encrypt(generatePassword());
 | 
			
		||||
		const postgresqlUser = cuid();
 | 
			
		||||
@@ -199,44 +211,157 @@ export async function configureServiceType({ id, type }) {
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
export async function setServiceVersion({ id, version }) {
 | 
			
		||||
 | 
			
		||||
export async function setServiceVersion({
 | 
			
		||||
	id,
 | 
			
		||||
	version
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	version: string;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { version }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function setServiceSettings({ id, dualCerts }) {
 | 
			
		||||
export async function setServiceSettings({
 | 
			
		||||
	id,
 | 
			
		||||
	dualCerts
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	dualCerts: boolean;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { dualCerts }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function updatePlausibleAnalyticsService({ id, fqdn, email, username, name }) {
 | 
			
		||||
export async function updatePlausibleAnalyticsService({
 | 
			
		||||
	id,
 | 
			
		||||
	fqdn,
 | 
			
		||||
	email,
 | 
			
		||||
	username,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	email: string;
 | 
			
		||||
	username: string;
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
	await prisma.plausibleAnalytics.update({ where: { serviceId: id }, data: { email, username } });
 | 
			
		||||
	await prisma.service.update({ where: { id }, data: { name, fqdn } });
 | 
			
		||||
}
 | 
			
		||||
export async function updateService({ id, fqdn, name }) {
 | 
			
		||||
 | 
			
		||||
export async function updateService({
 | 
			
		||||
	id,
 | 
			
		||||
	fqdn,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({ where: { id }, data: { fqdn, name } });
 | 
			
		||||
}
 | 
			
		||||
export async function updateWordpress({ id, fqdn, name, mysqlDatabase, extraConfig }) {
 | 
			
		||||
 | 
			
		||||
export async function updateLanguageToolService({
 | 
			
		||||
	id,
 | 
			
		||||
	fqdn,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({ where: { id }, data: { fqdn, name } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function updateMeiliSearchService({
 | 
			
		||||
	id,
 | 
			
		||||
	fqdn,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({ where: { id }, data: { fqdn, name } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function updateVaultWardenService({
 | 
			
		||||
	id,
 | 
			
		||||
	fqdn,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({ where: { id }, data: { fqdn, name } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function updateVsCodeServer({
 | 
			
		||||
	id,
 | 
			
		||||
	fqdn,
 | 
			
		||||
	name
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({ where: { id }, data: { fqdn, name } });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function updateWordpress({
 | 
			
		||||
	id,
 | 
			
		||||
	fqdn,
 | 
			
		||||
	name,
 | 
			
		||||
	mysqlDatabase,
 | 
			
		||||
	extraConfig
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	mysqlDatabase: string;
 | 
			
		||||
	extraConfig: string;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { fqdn, name, wordpress: { update: { mysqlDatabase, extraConfig } } }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
export async function updateMinioService({ id, publicPort }) {
 | 
			
		||||
 | 
			
		||||
export async function updateMinioService({
 | 
			
		||||
	id,
 | 
			
		||||
	publicPort
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	publicPort: number;
 | 
			
		||||
}): Promise<Minio> {
 | 
			
		||||
	return await prisma.minio.update({ where: { serviceId: id }, data: { publicPort } });
 | 
			
		||||
}
 | 
			
		||||
export async function updateGhostService({ id, fqdn, name, mariadbDatabase }) {
 | 
			
		||||
 | 
			
		||||
export async function updateGhostService({
 | 
			
		||||
	id,
 | 
			
		||||
	fqdn,
 | 
			
		||||
	name,
 | 
			
		||||
	mariadbDatabase
 | 
			
		||||
}: {
 | 
			
		||||
	id: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	mariadbDatabase: string;
 | 
			
		||||
}): Promise<Service> {
 | 
			
		||||
	return await prisma.service.update({
 | 
			
		||||
		where: { id },
 | 
			
		||||
		data: { fqdn, name, ghost: { update: { mariadbDatabase } } }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function removeService({ id }) {
 | 
			
		||||
export async function removeService({ id }: { id: string }): Promise<void> {
 | 
			
		||||
	await prisma.meiliSearch.deleteMany({ where: { serviceId: id } });
 | 
			
		||||
	await prisma.ghost.deleteMany({ where: { serviceId: id } });
 | 
			
		||||
	await prisma.plausibleAnalytics.deleteMany({ where: { serviceId: id } });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,9 @@
 | 
			
		||||
import { decrypt } from '$lib/crypto';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
import type { Setting } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export async function listSettings() {
 | 
			
		||||
	let settings = await prisma.setting.findFirst({});
 | 
			
		||||
export async function listSettings(): Promise<Setting> {
 | 
			
		||||
	const settings = await prisma.setting.findFirst({});
 | 
			
		||||
	if (settings.proxyPassword) settings.proxyPassword = decrypt(settings.proxyPassword);
 | 
			
		||||
	return settings;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
import type { Team, Permission } from '@prisma/client';
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
 | 
			
		||||
export async function listTeams() {
 | 
			
		||||
export async function listTeams(): Promise<Team[]> {
 | 
			
		||||
	return await prisma.team.findMany();
 | 
			
		||||
}
 | 
			
		||||
export async function newTeam({ name, userId }) {
 | 
			
		||||
export async function newTeam({ name, userId }: { name: string; userId: string }): Promise<Team> {
 | 
			
		||||
	return await prisma.team.create({
 | 
			
		||||
		data: {
 | 
			
		||||
			name,
 | 
			
		||||
@@ -12,7 +13,11 @@ export async function newTeam({ name, userId }) {
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
export async function getMyTeams({ userId }) {
 | 
			
		||||
export async function getMyTeams({
 | 
			
		||||
	userId
 | 
			
		||||
}: {
 | 
			
		||||
	userId: string;
 | 
			
		||||
}): Promise<(Permission & { team: Team & { _count: { users: number } } })[]> {
 | 
			
		||||
	return await prisma.permission.findMany({
 | 
			
		||||
		where: { userId },
 | 
			
		||||
		include: { team: { include: { _count: { select: { users: true } } } } }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,14 +3,28 @@ import bcrypt from 'bcryptjs';
 | 
			
		||||
 | 
			
		||||
import { prisma } from './common';
 | 
			
		||||
import { asyncExecShell, uniqueName } from '$lib/common';
 | 
			
		||||
 | 
			
		||||
import * as db from '$lib/database';
 | 
			
		||||
import { startCoolifyProxy } from '$lib/haproxy';
 | 
			
		||||
export async function hashPassword(password: string) {
 | 
			
		||||
import type { User } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export async function hashPassword(password: string): Promise<string> {
 | 
			
		||||
	const saltRounds = 15;
 | 
			
		||||
	return bcrypt.hash(password, saltRounds);
 | 
			
		||||
}
 | 
			
		||||
export async function login({ email, password, isLogin }) {
 | 
			
		||||
 | 
			
		||||
export async function login({
 | 
			
		||||
	email,
 | 
			
		||||
	password,
 | 
			
		||||
	isLogin
 | 
			
		||||
}: {
 | 
			
		||||
	email: string;
 | 
			
		||||
	password: string;
 | 
			
		||||
	isLogin: boolean;
 | 
			
		||||
}): Promise<{
 | 
			
		||||
	status: number;
 | 
			
		||||
	headers: { 'Set-Cookie': string };
 | 
			
		||||
	body: { userId: string; teamId: string; permission: string; isAdmin: boolean };
 | 
			
		||||
}> {
 | 
			
		||||
	const users = await prisma.user.count();
 | 
			
		||||
	const userFound = await prisma.user.findUnique({
 | 
			
		||||
		where: { email },
 | 
			
		||||
@@ -140,6 +154,6 @@ export async function login({ email, password, isLogin }) {
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getUser({ userId }) {
 | 
			
		||||
export async function getUser({ userId }: { userId: string }): Promise<User> {
 | 
			
		||||
	return await prisma.user.findUnique({ where: { id: userId } });
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import { toast } from '@zerodevx/svelte-toast';
 | 
			
		||||
export function errorNotification(message: string) {
 | 
			
		||||
 | 
			
		||||
export function errorNotification(message: string): void {
 | 
			
		||||
	console.error(message);
 | 
			
		||||
	if (typeof message !== 'string') {
 | 
			
		||||
		toast.push('Ooops, something is not okay, are you okay?');
 | 
			
		||||
@@ -30,7 +31,7 @@ export function enhance(
 | 
			
		||||
		e.preventDefault();
 | 
			
		||||
 | 
			
		||||
		let body = new FormData(form);
 | 
			
		||||
		let parsedData = body;
 | 
			
		||||
		const parsedData = body;
 | 
			
		||||
 | 
			
		||||
		body.forEach((data, key) => {
 | 
			
		||||
			if (data === '' || data === null) parsedData.delete(key);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,5 @@
 | 
			
		||||
import { dev } from '$app/env';
 | 
			
		||||
import got from 'got';
 | 
			
		||||
import mustache from 'mustache';
 | 
			
		||||
import crypto from 'crypto';
 | 
			
		||||
 | 
			
		||||
import got, { type Got } from 'got';
 | 
			
		||||
import * as db from '$lib/database';
 | 
			
		||||
import { checkContainer, checkHAProxy } from '.';
 | 
			
		||||
import { asyncExecShell, getDomain, getEngine } from '$lib/common';
 | 
			
		||||
@@ -10,7 +7,7 @@ import { supportedServiceTypesAndVersions } from '$lib/components/common';
 | 
			
		||||
 | 
			
		||||
const url = dev ? 'http://localhost:5555' : 'http://coolify-haproxy:5555';
 | 
			
		||||
 | 
			
		||||
let template = `program api 
 | 
			
		||||
const template = `program api 
 | 
			
		||||
  command /usr/bin/dataplaneapi -f /usr/local/etc/haproxy/dataplaneapi.hcl --userlist haproxy-dataplaneapi
 | 
			
		||||
  no option start-on-reload
 | 
			
		||||
	
 | 
			
		||||
@@ -128,7 +125,8 @@ backend {{domain}}
 | 
			
		||||
  server {{id}} {{id}}:{{port}} check fall 10
 | 
			
		||||
{{/coolify}}
 | 
			
		||||
`;
 | 
			
		||||
export async function haproxyInstance() {
 | 
			
		||||
 | 
			
		||||
export async function haproxyInstance(): Promise<Got> {
 | 
			
		||||
	const { proxyPassword } = await db.listSettings();
 | 
			
		||||
	return got.extend({
 | 
			
		||||
		prefixUrl: url,
 | 
			
		||||
@@ -137,11 +135,10 @@ export async function haproxyInstance() {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function configureHAProxy() {
 | 
			
		||||
export async function configureHAProxy(): Promise<void> {
 | 
			
		||||
	const haproxy = await haproxyInstance();
 | 
			
		||||
	await checkHAProxy(haproxy);
 | 
			
		||||
 | 
			
		||||
	try {
 | 
			
		||||
	const data = {
 | 
			
		||||
		applications: [],
 | 
			
		||||
		services: [],
 | 
			
		||||
@@ -192,7 +189,7 @@ export async function configureHAProxy() {
 | 
			
		||||
						.map((c) => c.replace(/"/g, ''));
 | 
			
		||||
					if (containers.length > 0) {
 | 
			
		||||
						for (const container of containers) {
 | 
			
		||||
								let previewDomain = `${container.split('-')[1]}.${domain}`;
 | 
			
		||||
							const previewDomain = `${container.split('-')[1]}.${domain}`;
 | 
			
		||||
							data.applications.push({
 | 
			
		||||
								id: container,
 | 
			
		||||
								port: port || 3000,
 | 
			
		||||
@@ -265,23 +262,36 @@ export async function configureHAProxy() {
 | 
			
		||||
			redirectValue,
 | 
			
		||||
			redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain
 | 
			
		||||
		});
 | 
			
		||||
		}
 | 
			
		||||
		const output = mustache.render(template, data);
 | 
			
		||||
		const newHash = crypto.createHash('md5').update(output).digest('hex');
 | 
			
		||||
		const { proxyHash, id } = await db.listSettings();
 | 
			
		||||
		if (proxyHash !== newHash) {
 | 
			
		||||
			await db.prisma.setting.update({ where: { id }, data: { proxyHash: newHash } });
 | 
			
		||||
			await haproxy.post(`v2/services/haproxy/configuration/raw`, {
 | 
			
		||||
				searchParams: {
 | 
			
		||||
					skip_version: true
 | 
			
		||||
				},
 | 
			
		||||
				body: output,
 | 
			
		||||
				headers: {
 | 
			
		||||
					'Content-Type': 'text/plain'
 | 
			
		||||
				}
 | 
			
		||||
		for (const service of services) {
 | 
			
		||||
			const { fqdn, id, type, destinationDocker, destinationDockerId, updatedAt } = service;
 | 
			
		||||
			if (destinationDockerId) {
 | 
			
		||||
				const { engine } = destinationDocker;
 | 
			
		||||
				const found = supportedServiceTypesAndVersions.find((a) => a.name === type);
 | 
			
		||||
				if (found) {
 | 
			
		||||
					const port = found.ports.main;
 | 
			
		||||
					const publicPort = service[type]?.publicPort;
 | 
			
		||||
					const isRunning = await checkContainer(engine, id);
 | 
			
		||||
					if (fqdn) {
 | 
			
		||||
						const domain = getDomain(fqdn);
 | 
			
		||||
						const isHttps = fqdn.startsWith('https://');
 | 
			
		||||
						const isWWW = fqdn.includes('www.');
 | 
			
		||||
						const redirectValue = `${isHttps ? 'https://' : 'http://'}${domain}%[capture.req.uri]`;
 | 
			
		||||
						if (isRunning) {
 | 
			
		||||
							data.services.push({
 | 
			
		||||
								id,
 | 
			
		||||
								port,
 | 
			
		||||
								publicPort,
 | 
			
		||||
								domain,
 | 
			
		||||
								isRunning,
 | 
			
		||||
								isHttps,
 | 
			
		||||
								redirectValue,
 | 
			
		||||
								redirectTo: isWWW ? domain.replace('www.', '') : 'www.' + domain,
 | 
			
		||||
								updatedAt: updatedAt.getTime()
 | 
			
		||||
							});
 | 
			
		||||
						}
 | 
			
		||||
	} catch (error) {
 | 
			
		||||
		throw error;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
import { dev } from '$app/env';
 | 
			
		||||
import { asyncExecShell, getEngine } from '$lib/common';
 | 
			
		||||
import got from 'got';
 | 
			
		||||
import got, { type Got, type Response } from 'got';
 | 
			
		||||
import * as db from '$lib/database';
 | 
			
		||||
import type { DestinationDocker } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
const url = dev ? 'http://localhost:5555' : 'http://coolify-haproxy:5555';
 | 
			
		||||
 | 
			
		||||
@@ -9,7 +10,7 @@ export const defaultProxyImage = `coolify-haproxy-alpine:latest`;
 | 
			
		||||
export const defaultProxyImageTcp = `coolify-haproxy-tcp-alpine:latest`;
 | 
			
		||||
export const defaultProxyImageHttp = `coolify-haproxy-http-alpine:latest`;
 | 
			
		||||
 | 
			
		||||
export async function haproxyInstance() {
 | 
			
		||||
export async function haproxyInstance(): Promise<Got> {
 | 
			
		||||
	const { proxyPassword } = await db.listSettings();
 | 
			
		||||
	return got.extend({
 | 
			
		||||
		prefixUrl: url,
 | 
			
		||||
@@ -17,6 +18,7 @@ export async function haproxyInstance() {
 | 
			
		||||
		password: proxyPassword
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getRawConfiguration(): Promise<RawHaproxyConfiguration> {
 | 
			
		||||
	return await (await haproxyInstance()).get(`v2/services/haproxy/configuration/raw`).json();
 | 
			
		||||
}
 | 
			
		||||
@@ -43,11 +45,12 @@ export async function getNextTransactionId(): Promise<string> {
 | 
			
		||||
	return newTransaction.id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function completeTransaction(transactionId) {
 | 
			
		||||
export async function completeTransaction(transactionId: string): Promise<Response<string>> {
 | 
			
		||||
	const haproxy = await haproxyInstance();
 | 
			
		||||
	return await haproxy.put(`v2/services/haproxy/transactions/${transactionId}`);
 | 
			
		||||
}
 | 
			
		||||
export async function deleteProxy({ id }) {
 | 
			
		||||
 | 
			
		||||
export async function deleteProxy({ id }: { id: string }): Promise<void> {
 | 
			
		||||
	const haproxy = await haproxyInstance();
 | 
			
		||||
	await checkHAProxy(haproxy);
 | 
			
		||||
 | 
			
		||||
@@ -77,11 +80,12 @@ export async function deleteProxy({ id }) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function reloadHaproxy(engine) {
 | 
			
		||||
export async function reloadHaproxy(engine: string): Promise<{ stdout: string; stderr: string }> {
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
	return await asyncExecShell(`DOCKER_HOST=${host} docker exec coolify-haproxy kill -HUP 1`);
 | 
			
		||||
}
 | 
			
		||||
export async function checkHAProxy(haproxy?: any) {
 | 
			
		||||
 | 
			
		||||
export async function checkHAProxy(haproxy?: Got): Promise<void> {
 | 
			
		||||
	if (!haproxy) haproxy = await haproxyInstance();
 | 
			
		||||
	try {
 | 
			
		||||
		await haproxy.get('v2/info');
 | 
			
		||||
@@ -93,7 +97,10 @@ export async function checkHAProxy(haproxy?: any) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function stopTcpHttpProxy(destinationDocker, publicPort) {
 | 
			
		||||
export async function stopTcpHttpProxy(
 | 
			
		||||
	destinationDocker: DestinationDocker,
 | 
			
		||||
	publicPort: number
 | 
			
		||||
): Promise<{ stdout: string; stderr: string } | Error> {
 | 
			
		||||
	const { engine } = destinationDocker;
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
	const containerName = `haproxy-for-${publicPort}`;
 | 
			
		||||
@@ -108,7 +115,13 @@ export async function stopTcpHttpProxy(destinationDocker, publicPort) {
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
export async function startTcpProxy(destinationDocker, id, publicPort, privatePort, volume = null) {
 | 
			
		||||
export async function startTcpProxy(
 | 
			
		||||
	destinationDocker: DestinationDocker,
 | 
			
		||||
	id: string,
 | 
			
		||||
	publicPort: number,
 | 
			
		||||
	privatePort: number,
 | 
			
		||||
	volume?: string
 | 
			
		||||
): Promise<{ stdout: string; stderr: string } | Error> {
 | 
			
		||||
	const { network, engine } = destinationDocker;
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
 | 
			
		||||
@@ -132,7 +145,13 @@ export async function startTcpProxy(destinationDocker, id, publicPort, privatePo
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
export async function startHttpProxy(destinationDocker, id, publicPort, privatePort) {
 | 
			
		||||
 | 
			
		||||
export async function startHttpProxy(
 | 
			
		||||
	destinationDocker: DestinationDocker,
 | 
			
		||||
	id: string,
 | 
			
		||||
	publicPort: number,
 | 
			
		||||
	privatePort: number
 | 
			
		||||
): Promise<{ stdout: string; stderr: string } | Error> {
 | 
			
		||||
	const { network, engine } = destinationDocker;
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
 | 
			
		||||
@@ -154,7 +173,8 @@ export async function startHttpProxy(destinationDocker, id, publicPort, privateP
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
export async function startCoolifyProxy(engine) {
 | 
			
		||||
 | 
			
		||||
export async function startCoolifyProxy(engine: string): Promise<void> {
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
	const found = await checkContainer(engine, 'coolify-haproxy');
 | 
			
		||||
	const { proxyPassword, proxyUser, id } = await db.listSettings();
 | 
			
		||||
@@ -170,7 +190,8 @@ export async function startCoolifyProxy(engine) {
 | 
			
		||||
	}
 | 
			
		||||
	await configureNetworkCoolifyProxy(engine);
 | 
			
		||||
}
 | 
			
		||||
export async function checkContainer(engine, container) {
 | 
			
		||||
 | 
			
		||||
export async function checkContainer(engine: string, container: string): Promise<boolean> {
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
	let containerFound = false;
 | 
			
		||||
 | 
			
		||||
@@ -180,7 +201,7 @@ export async function checkContainer(engine, container) {
 | 
			
		||||
		);
 | 
			
		||||
		const parsedStdout = JSON.parse(stdout);
 | 
			
		||||
		const status = parsedStdout.Status;
 | 
			
		||||
		const isRunning = status === 'running' ? true : false;
 | 
			
		||||
		const isRunning = status === 'running';
 | 
			
		||||
		if (status === 'exited' || status === 'created') {
 | 
			
		||||
			await asyncExecShell(`DOCKER_HOST="${host}" docker rm ${container}`);
 | 
			
		||||
		}
 | 
			
		||||
@@ -193,7 +214,9 @@ export async function checkContainer(engine, container) {
 | 
			
		||||
	return containerFound;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function stopCoolifyProxy(engine) {
 | 
			
		||||
export async function stopCoolifyProxy(
 | 
			
		||||
	engine: string
 | 
			
		||||
): Promise<{ stdout: string; stderr: string } | Error> {
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
	const found = await checkContainer(engine, 'coolify-haproxy');
 | 
			
		||||
	await db.setDestinationSettings({ engine, isCoolifyProxyUsed: false });
 | 
			
		||||
@@ -210,16 +233,12 @@ export async function stopCoolifyProxy(engine) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function configureNetworkCoolifyProxy(engine) {
 | 
			
		||||
export async function configureNetworkCoolifyProxy(engine: string): Promise<void> {
 | 
			
		||||
	const host = getEngine(engine);
 | 
			
		||||
	const destinations = await db.prisma.destinationDocker.findMany({ where: { engine } });
 | 
			
		||||
	destinations.forEach(async (destination) => {
 | 
			
		||||
		try {
 | 
			
		||||
	for (const destination of destinations) {
 | 
			
		||||
		await asyncExecShell(
 | 
			
		||||
			`DOCKER_HOST="${host}" docker network connect ${destination.network} coolify-haproxy`
 | 
			
		||||
		);
 | 
			
		||||
		} catch (err) {
 | 
			
		||||
			// TODO: handle error
 | 
			
		||||
	}
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,9 @@ import { asyncExecShell, saveBuildLog } from '$lib/common';
 | 
			
		||||
import got from 'got';
 | 
			
		||||
import jsonwebtoken from 'jsonwebtoken';
 | 
			
		||||
import * as db from '$lib/database';
 | 
			
		||||
import { ErrorHandler } from '$lib/database';
 | 
			
		||||
 | 
			
		||||
export default async function ({
 | 
			
		||||
	applicationId,
 | 
			
		||||
	debug,
 | 
			
		||||
	workdir,
 | 
			
		||||
	githubAppId,
 | 
			
		||||
	repository,
 | 
			
		||||
@@ -14,7 +12,16 @@ export default async function ({
 | 
			
		||||
	htmlUrl,
 | 
			
		||||
	branch,
 | 
			
		||||
	buildId
 | 
			
		||||
}): Promise<any> {
 | 
			
		||||
}: {
 | 
			
		||||
	applicationId: string;
 | 
			
		||||
	workdir: string;
 | 
			
		||||
	githubAppId: string;
 | 
			
		||||
	repository: string;
 | 
			
		||||
	apiUrl: string;
 | 
			
		||||
	htmlUrl: string;
 | 
			
		||||
	branch: string;
 | 
			
		||||
	buildId: string;
 | 
			
		||||
}): Promise<string> {
 | 
			
		||||
	const url = htmlUrl.replace('https://', '').replace('http://', '');
 | 
			
		||||
	await saveBuildLog({ line: 'GitHub importer started.', buildId, applicationId });
 | 
			
		||||
	const { privateKey, appId, installationId } = await db.getUniqueGithubApp({ githubAppId });
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,16 @@ export default async function ({
 | 
			
		||||
	branch,
 | 
			
		||||
	buildId,
 | 
			
		||||
	privateSshKey
 | 
			
		||||
}): Promise<any> {
 | 
			
		||||
}: {
 | 
			
		||||
	applicationId: string;
 | 
			
		||||
	workdir: string;
 | 
			
		||||
	repository: string;
 | 
			
		||||
	htmlUrl: string;
 | 
			
		||||
	branch: string;
 | 
			
		||||
	buildId: string;
 | 
			
		||||
	repodir: string;
 | 
			
		||||
	privateSshKey: string;
 | 
			
		||||
}): Promise<string> {
 | 
			
		||||
	const url = htmlUrl.replace('https://', '').replace('http://', '').replace(/\/$/, '');
 | 
			
		||||
	await saveBuildLog({ line: 'GitLab importer started.', buildId, applicationId });
 | 
			
		||||
	await asyncExecShell(`echo '${privateSshKey}' > ${repodir}/id.rsa`);
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ import fs from 'fs/promises';
 | 
			
		||||
import getPort, { portNumbers } from 'get-port';
 | 
			
		||||
import { supportedServiceTypesAndVersions } from '$lib/components/common';
 | 
			
		||||
 | 
			
		||||
export async function letsEncrypt(domain, id = null, isCoolify = false) {
 | 
			
		||||
export async function letsEncrypt(domain: string, id?: string, isCoolify = false): Promise<void> {
 | 
			
		||||
	try {
 | 
			
		||||
		const data = await db.prisma.setting.findFirst();
 | 
			
		||||
		const { minPort, maxPort } = data;
 | 
			
		||||
@@ -98,7 +98,7 @@ export async function letsEncrypt(domain, id = null, isCoolify = false) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function generateSSLCerts() {
 | 
			
		||||
export async function generateSSLCerts(): Promise<void> {
 | 
			
		||||
	const ssls = [];
 | 
			
		||||
	const applications = await db.prisma.application.findMany({
 | 
			
		||||
		include: { destinationDocker: true, settings: true },
 | 
			
		||||
@@ -131,7 +131,7 @@ export async function generateSSLCerts() {
 | 
			
		||||
						.map((c) => c.replace(/"/g, ''));
 | 
			
		||||
					if (containers.length > 0) {
 | 
			
		||||
						for (const container of containers) {
 | 
			
		||||
							let previewDomain = `${container.split('-')[1]}.${domain}`;
 | 
			
		||||
							const previewDomain = `${container.split('-')[1]}.${domain}`;
 | 
			
		||||
							if (isHttps) ssls.push({ domain: previewDomain, id, isCoolify: false });
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,27 +20,22 @@ import {
 | 
			
		||||
	setDefaultConfiguration
 | 
			
		||||
} from '$lib/buildPacks/common';
 | 
			
		||||
import yaml from 'js-yaml';
 | 
			
		||||
import type { Job } from 'bullmq';
 | 
			
		||||
import type { BuilderJob } from '$lib/types/builderJob';
 | 
			
		||||
 | 
			
		||||
import type { ComposeFile } from '$lib/types/composeFile';
 | 
			
		||||
 | 
			
		||||
export default async function (job) {
 | 
			
		||||
	let {
 | 
			
		||||
export default async function (job: Job<BuilderJob, void, string>): Promise<void> {
 | 
			
		||||
	const {
 | 
			
		||||
		id: applicationId,
 | 
			
		||||
		repository,
 | 
			
		||||
		branch,
 | 
			
		||||
		buildPack,
 | 
			
		||||
		name,
 | 
			
		||||
		destinationDocker,
 | 
			
		||||
		destinationDockerId,
 | 
			
		||||
		gitSource,
 | 
			
		||||
		build_id: buildId,
 | 
			
		||||
		configHash,
 | 
			
		||||
		port,
 | 
			
		||||
		installCommand,
 | 
			
		||||
		buildCommand,
 | 
			
		||||
		startCommand,
 | 
			
		||||
		fqdn,
 | 
			
		||||
		baseDirectory,
 | 
			
		||||
		publishDirectory,
 | 
			
		||||
		projectId,
 | 
			
		||||
		secrets,
 | 
			
		||||
		phpModules,
 | 
			
		||||
@@ -53,6 +48,16 @@ export default async function (job) {
 | 
			
		||||
		pythonModule,
 | 
			
		||||
		pythonVariable
 | 
			
		||||
	} = job.data;
 | 
			
		||||
	let {
 | 
			
		||||
		branch,
 | 
			
		||||
		buildPack,
 | 
			
		||||
		port,
 | 
			
		||||
		installCommand,
 | 
			
		||||
		buildCommand,
 | 
			
		||||
		startCommand,
 | 
			
		||||
		baseDirectory,
 | 
			
		||||
		publishDirectory
 | 
			
		||||
	} = job.data;
 | 
			
		||||
	const { debug } = settings;
 | 
			
		||||
 | 
			
		||||
	await asyncSleep(500);
 | 
			
		||||
@@ -67,7 +72,7 @@ export default async function (job) {
 | 
			
		||||
	});
 | 
			
		||||
	let imageId = applicationId;
 | 
			
		||||
	let domain = getDomain(fqdn);
 | 
			
		||||
	let volumes =
 | 
			
		||||
	const volumes =
 | 
			
		||||
		persistentStorage?.map((storage) => {
 | 
			
		||||
			return `${applicationId}${storage.path.replace(/\//gi, '-')}:${
 | 
			
		||||
				buildPack !== 'docker' ? '/app' : ''
 | 
			
		||||
@@ -103,7 +108,7 @@ export default async function (job) {
 | 
			
		||||
		publishDirectory = configuration.publishDirectory;
 | 
			
		||||
		baseDirectory = configuration.baseDirectory;
 | 
			
		||||
 | 
			
		||||
		let commit = await importers[gitSource.type]({
 | 
			
		||||
		const commit = await importers[gitSource.type]({
 | 
			
		||||
			applicationId,
 | 
			
		||||
			debug,
 | 
			
		||||
			workdir,
 | 
			
		||||
@@ -210,9 +215,7 @@ export default async function (job) {
 | 
			
		||||
				await saveBuildLog({ line: `Build pack ${buildPack} not found`, buildId, applicationId });
 | 
			
		||||
				throw new Error(`Build pack ${buildPack} not found.`);
 | 
			
		||||
			}
 | 
			
		||||
			deployNeeded = true;
 | 
			
		||||
		} else {
 | 
			
		||||
			deployNeeded = false;
 | 
			
		||||
			await saveBuildLog({ line: 'Nothing changed.', buildId, applicationId });
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,6 @@
 | 
			
		||||
import { dev } from '$app/env';
 | 
			
		||||
import { asyncExecShell, getEngine, version } from '$lib/common';
 | 
			
		||||
import { prisma } from '$lib/database';
 | 
			
		||||
import { defaultProxyImageHttp, defaultProxyImageTcp } from '$lib/haproxy';
 | 
			
		||||
export default async function () {
 | 
			
		||||
export default async function (): Promise<void> {
 | 
			
		||||
	const destinationDockers = await prisma.destinationDocker.findMany();
 | 
			
		||||
	for (const destinationDocker of destinationDockers) {
 | 
			
		||||
		const host = getEngine(destinationDocker.engine);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,8 @@
 | 
			
		||||
import * as Bullmq from 'bullmq';
 | 
			
		||||
import { default as ProdBullmq, Job, QueueEvents, QueueScheduler } from 'bullmq';
 | 
			
		||||
import cuid from 'cuid';
 | 
			
		||||
import { default as ProdBullmq, QueueScheduler } from 'bullmq';
 | 
			
		||||
import { dev } from '$app/env';
 | 
			
		||||
import { prisma } from '$lib/database';
 | 
			
		||||
 | 
			
		||||
import builder from './builder';
 | 
			
		||||
import logger from './logger';
 | 
			
		||||
import cleanup from './cleanup';
 | 
			
		||||
import proxy from './proxy';
 | 
			
		||||
import ssl from './ssl';
 | 
			
		||||
@@ -28,7 +25,7 @@ const connectionOptions = {
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cron = async () => {
 | 
			
		||||
const cron = async (): Promise<void> => {
 | 
			
		||||
	new QueueScheduler('proxy', connectionOptions);
 | 
			
		||||
	new QueueScheduler('cleanup', connectionOptions);
 | 
			
		||||
	new QueueScheduler('ssl', connectionOptions);
 | 
			
		||||
@@ -89,18 +86,6 @@ const cron = async () => {
 | 
			
		||||
	await queue.ssl.add('ssl', {}, { repeat: { every: dev ? 10000 : 60000 } });
 | 
			
		||||
	if (!dev) await queue.cleanup.add('cleanup', {}, { repeat: { every: 300000 } });
 | 
			
		||||
	await queue.sslRenew.add('sslRenew', {}, { repeat: { every: 1800000 } });
 | 
			
		||||
 | 
			
		||||
	const events = {
 | 
			
		||||
		proxy: new QueueEvents('proxy', { ...connectionOptions }),
 | 
			
		||||
		ssl: new QueueEvents('ssl', { ...connectionOptions })
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	events.proxy.on('completed', (data) => {
 | 
			
		||||
		// console.log(data)
 | 
			
		||||
	});
 | 
			
		||||
	events.ssl.on('completed', (data) => {
 | 
			
		||||
		// console.log(data)
 | 
			
		||||
	});
 | 
			
		||||
};
 | 
			
		||||
cron().catch((error) => {
 | 
			
		||||
	console.log('cron failed to start');
 | 
			
		||||
@@ -157,9 +142,5 @@ buildWorker.on('failed', async (job: Bullmq.Job, failedReason) => {
 | 
			
		||||
 | 
			
		||||
const buildLogQueueName = 'log_queue';
 | 
			
		||||
const buildLogQueue = new Queue(buildLogQueueName, connectionOptions);
 | 
			
		||||
const buildLogWorker = new Worker(buildLogQueueName, async (job) => await logger(job), {
 | 
			
		||||
	concurrency: 1,
 | 
			
		||||
	...connectionOptions
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export { buildQueue, buildLogQueue };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
import { prisma } from '$lib/database';
 | 
			
		||||
import { dev } from '$app/env';
 | 
			
		||||
import type { Job } from 'bullmq';
 | 
			
		||||
 | 
			
		||||
export default async function (job) {
 | 
			
		||||
export default async function (job: Job): Promise<void> {
 | 
			
		||||
	const { line, applicationId, buildId } = job.data;
 | 
			
		||||
	if (dev) console.debug(`[${applicationId}] ${line}`);
 | 
			
		||||
	await prisma.buildLog.create({ data: { line, buildId, time: Number(job.id), applicationId } });
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
import { ErrorHandler } from '$lib/database';
 | 
			
		||||
import { configureHAProxy } from '$lib/haproxy/configuration';
 | 
			
		||||
 | 
			
		||||
export default async function () {
 | 
			
		||||
export default async function (): Promise<void | {
 | 
			
		||||
	status: number;
 | 
			
		||||
	body: { message: string; error: string };
 | 
			
		||||
}> {
 | 
			
		||||
	try {
 | 
			
		||||
		return await configureHAProxy();
 | 
			
		||||
	} catch (error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { generateSSLCerts } from '$lib/letsencrypt';
 | 
			
		||||
 | 
			
		||||
export default async function () {
 | 
			
		||||
export default async function (): Promise<void> {
 | 
			
		||||
	try {
 | 
			
		||||
		return await generateSSLCerts();
 | 
			
		||||
	} catch (error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,9 @@
 | 
			
		||||
import { asyncExecShell } from '$lib/common';
 | 
			
		||||
import { reloadHaproxy } from '$lib/haproxy';
 | 
			
		||||
 | 
			
		||||
export default async function () {
 | 
			
		||||
	try {
 | 
			
		||||
export default async function (): Promise<void> {
 | 
			
		||||
	await asyncExecShell(
 | 
			
		||||
		`docker run --rm --name certbot-renewal -v "coolify-letsencrypt:/etc/letsencrypt" certbot/certbot --logs-dir /etc/letsencrypt/logs renew`
 | 
			
		||||
	);
 | 
			
		||||
	await reloadHaproxy('unix:///var/run/docker.sock');
 | 
			
		||||
	} catch (error) {
 | 
			
		||||
		throw error;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
import { writable } from 'svelte/store';
 | 
			
		||||
import { writable, type Writable } from 'svelte/store';
 | 
			
		||||
 | 
			
		||||
export const gitTokens = writable({
 | 
			
		||||
export const gitTokens: Writable<{ githubToken: string | null; gitlabToken: string | null }> =
 | 
			
		||||
	writable({
 | 
			
		||||
		githubToken: null,
 | 
			
		||||
		gitlabToken: null
 | 
			
		||||
});
 | 
			
		||||
	});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								src/lib/types/builderJob.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/lib/types/builderJob.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
import type { DestinationDocker, GithubApp, GitlabApp, GitSource, Secret } from '@prisma/client';
 | 
			
		||||
 | 
			
		||||
export type BuilderJob = {
 | 
			
		||||
	build_id: string;
 | 
			
		||||
	type: BuildType;
 | 
			
		||||
	id: string;
 | 
			
		||||
	name: string;
 | 
			
		||||
	fqdn: string;
 | 
			
		||||
	repository: string;
 | 
			
		||||
	configHash: unknown;
 | 
			
		||||
	branch: string;
 | 
			
		||||
	buildPack: BuildPackName;
 | 
			
		||||
	projectId: number;
 | 
			
		||||
	port: number;
 | 
			
		||||
	installCommand: string;
 | 
			
		||||
	buildCommand?: string;
 | 
			
		||||
	startCommand?: string;
 | 
			
		||||
	baseDirectory: string;
 | 
			
		||||
	publishDirectory: string;
 | 
			
		||||
	phpModules: string;
 | 
			
		||||
	pythonWSGI: string;
 | 
			
		||||
	pythonModule: string;
 | 
			
		||||
	pythonVariable: string;
 | 
			
		||||
	createdAt: string;
 | 
			
		||||
	updatedAt: string;
 | 
			
		||||
	destinationDockerId: string;
 | 
			
		||||
	destinationDocker: DestinationDocker;
 | 
			
		||||
	gitSource: GitSource & { githubApp?: GithubApp; gitlabApp?: GitlabApp };
 | 
			
		||||
	settings: BuilderJobSettings;
 | 
			
		||||
	secrets: Secret[];
 | 
			
		||||
	persistentStorage: { path: string }[];
 | 
			
		||||
	pullmergeRequestId?: unknown;
 | 
			
		||||
	sourceBranch?: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// TODO: Add the other build types
 | 
			
		||||
export type BuildType = 'manual';
 | 
			
		||||
 | 
			
		||||
// TODO: Add the other buildpack names
 | 
			
		||||
export type BuildPackName = 'node' | 'docker';
 | 
			
		||||
 | 
			
		||||
export type BuilderJobSettings = {
 | 
			
		||||
	id: string;
 | 
			
		||||
	applicationId: string;
 | 
			
		||||
	dualCerts: boolean;
 | 
			
		||||
	debug: boolean;
 | 
			
		||||
	previews: boolean;
 | 
			
		||||
	autodeploy: boolean;
 | 
			
		||||
	createdAt: string;
 | 
			
		||||
	updatedAt: string;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										8
									
								
								src/lib/types/destinations.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/lib/types/destinations.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
export type CreateDockerDestination = {
 | 
			
		||||
	name: string;
 | 
			
		||||
	engine: string;
 | 
			
		||||
	remoteEngine: boolean;
 | 
			
		||||
	network: string;
 | 
			
		||||
	isCoolifyProxyUsed: boolean;
 | 
			
		||||
	teamId: string;
 | 
			
		||||
};
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { getTeam, getUserDetails } from '$lib/common';
 | 
			
		||||
import { getUserDetails } from '$lib/common';
 | 
			
		||||
import * as db from '$lib/database';
 | 
			
		||||
import { ErrorHandler } from '$lib/database';
 | 
			
		||||
import type { RequestHandler } from '@sveltejs/kit';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,43 +1,22 @@
 | 
			
		||||
import { asyncExecShell, getUserDetails } from '$lib/common';
 | 
			
		||||
import { getUserDetails } from '$lib/common';
 | 
			
		||||
import * as db from '$lib/database';
 | 
			
		||||
import { ErrorHandler } from '$lib/database';
 | 
			
		||||
import { dockerInstance } from '$lib/docker';
 | 
			
		||||
import type { RequestHandler } from '@sveltejs/kit';
 | 
			
		||||
import type { CreateDockerDestination } from '$lib/types/destinations';
 | 
			
		||||
 | 
			
		||||
export const post: RequestHandler = async (event) => {
 | 
			
		||||
	const { teamId, status, body } = await getUserDetails(event);
 | 
			
		||||
	if (status === 401) return { status, body };
 | 
			
		||||
 | 
			
		||||
	const {
 | 
			
		||||
		name,
 | 
			
		||||
		engine,
 | 
			
		||||
		network,
 | 
			
		||||
		isCoolifyProxyUsed,
 | 
			
		||||
		remoteEngine,
 | 
			
		||||
		ipAddress,
 | 
			
		||||
		user,
 | 
			
		||||
		port,
 | 
			
		||||
		sshPrivateKey
 | 
			
		||||
	} = await event.request.json();
 | 
			
		||||
	const dockerDestinationProps = {
 | 
			
		||||
		...((await event.request.json()) as Omit<CreateDockerDestination, 'teamId'>),
 | 
			
		||||
		teamId
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	try {
 | 
			
		||||
		let id = null;
 | 
			
		||||
		if (remoteEngine) {
 | 
			
		||||
			id = await db.newRemoteDestination({
 | 
			
		||||
				name,
 | 
			
		||||
				teamId,
 | 
			
		||||
				engine,
 | 
			
		||||
				network,
 | 
			
		||||
				isCoolifyProxyUsed,
 | 
			
		||||
				remoteEngine,
 | 
			
		||||
				ipAddress,
 | 
			
		||||
				user,
 | 
			
		||||
				port,
 | 
			
		||||
				sshPrivateKey
 | 
			
		||||
			});
 | 
			
		||||
		} else {
 | 
			
		||||
			id = await db.newLocalDestination({ name, teamId, engine, network, isCoolifyProxyUsed });
 | 
			
		||||
		}
 | 
			
		||||
		const id = dockerDestinationProps.remoteEngine
 | 
			
		||||
			? await db.newRemoteDestination(dockerDestinationProps)
 | 
			
		||||
			: await db.newLocalDestination(dockerDestinationProps);
 | 
			
		||||
		return { status: 200, body: { id } };
 | 
			
		||||
	} catch (error) {
 | 
			
		||||
		return ErrorHandler(error);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user