fix: cleanupStuckedContainers

This commit is contained in:
Andras Bacsai
2023-01-23 10:37:14 +01:00
parent 18ed2527e8
commit ade7c8566d
415 changed files with 9686 additions and 6 deletions

View File

@@ -0,0 +1,43 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var context_exports = {};
__export(context_exports, {
createContext: () => createContext
});
module.exports = __toCommonJS(context_exports);
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
var import_env = require("../env");
function createContext({ req }) {
const token = req.headers.authorization;
let user = null;
if (token) {
user = import_jsonwebtoken.default.verify(token, import_env.env.COOLIFY_SECRET_KEY);
}
return { user, hostname: req.hostname };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createContext
});

View File

@@ -0,0 +1,39 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var trpc_exports = {};
__export(trpc_exports, {
appRouter: () => appRouter
});
module.exports = __toCommonJS(trpc_exports);
var import_trpc = require("./trpc");
var import_routers = require("./routers");
const appRouter = (0, import_trpc.router)({
settings: import_routers.settingsRouter,
auth: import_routers.authRouter,
dashboard: import_routers.dashboardRouter,
applications: import_routers.applicationsRouter,
services: import_routers.servicesRouter,
databases: import_routers.databasesRouter,
sources: import_routers.sourcesRouter,
destinations: import_routers.destinationsRouter
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
appRouter
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,526 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var lib_exports = {};
__export(lib_exports, {
deployApplication: () => deployApplication,
generateConfigHash: () => generateConfigHash,
getApplicationFromDB: () => getApplicationFromDB,
setDefaultBaseImage: () => setDefaultBaseImage
});
module.exports = __toCommonJS(lib_exports);
var import_cuid = __toESM(require("cuid"));
var import_node_crypto = __toESM(require("node:crypto"));
var import_common = require("../../../lib/common");
var import_prisma = require("../../../prisma");
async function deployApplication(id, teamId, forceRebuild, pullmergeRequestId = null, branch = null) {
const buildId = (0, import_cuid.default)();
const application = await getApplicationFromDB(id, teamId);
if (application) {
if (!application?.configHash) {
await generateConfigHash(
id,
application.buildPack,
application.port,
application.exposePort,
application.installCommand,
application.buildCommand,
application.startCommand
);
}
await import_prisma.prisma.application.update({ where: { id }, data: { updatedAt: new Date() } });
if (application.gitSourceId) {
await import_prisma.prisma.build.create({
data: {
id: buildId,
applicationId: id,
sourceBranch: branch,
branch: application.branch,
pullmergeRequestId: pullmergeRequestId?.toString(),
forceRebuild,
destinationDockerId: application.destinationDocker?.id,
gitSourceId: application.gitSource?.id,
githubAppId: application.gitSource?.githubApp?.id,
gitlabAppId: application.gitSource?.gitlabApp?.id,
status: "queued",
type: pullmergeRequestId ? application.gitSource?.githubApp?.id ? "manual_pr" : "manual_mr" : "manual"
}
});
} else {
await import_prisma.prisma.build.create({
data: {
id: buildId,
applicationId: id,
branch: "latest",
forceRebuild,
destinationDockerId: application.destinationDocker?.id,
status: "queued",
type: "manual"
}
});
}
return buildId;
}
throw { status: 500, message: "Application cannot be deployed." };
}
async function generateConfigHash(id, buildPack, port, exposePort, installCommand, buildCommand, startCommand) {
const configHash = import_node_crypto.default.createHash("sha256").update(
JSON.stringify({
buildPack,
port,
exposePort,
installCommand,
buildCommand,
startCommand
})
).digest("hex");
return await import_prisma.prisma.application.update({ where: { id }, data: { configHash } });
}
async function getApplicationFromDB(id, teamId) {
let application = await import_prisma.prisma.application.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: {
destinationDocker: true,
settings: true,
gitSource: { include: { githubApp: true, gitlabApp: true } },
secrets: true,
persistentStorage: true,
connectedDatabase: true,
previewApplication: true,
dockerRegistry: true
}
});
if (!application) {
throw { status: 404, message: "Application not found." };
}
application = decryptApplication(application);
const buildPack = application?.buildPack || null;
const { baseImage, baseBuildImage, baseBuildImages, baseImages } = setDefaultBaseImage(buildPack);
if (application && !application.baseImage) {
application.baseImage = baseImage;
}
if (application && !application.baseBuildImage) {
application.baseBuildImage = baseBuildImage;
}
return { ...application, baseBuildImages, baseImages };
}
function decryptApplication(application) {
if (application) {
if (application?.gitSource?.githubApp?.clientSecret) {
application.gitSource.githubApp.clientSecret = (0, import_common.decrypt)(application.gitSource.githubApp.clientSecret) || null;
}
if (application?.gitSource?.githubApp?.webhookSecret) {
application.gitSource.githubApp.webhookSecret = (0, import_common.decrypt)(application.gitSource.githubApp.webhookSecret) || null;
}
if (application?.gitSource?.githubApp?.privateKey) {
application.gitSource.githubApp.privateKey = (0, import_common.decrypt)(application.gitSource.githubApp.privateKey) || null;
}
if (application?.gitSource?.gitlabApp?.appSecret) {
application.gitSource.gitlabApp.appSecret = (0, import_common.decrypt)(application.gitSource.gitlabApp.appSecret) || null;
}
if (application?.secrets.length > 0) {
application.secrets = application.secrets.map((s) => {
s.value = (0, import_common.decrypt)(s.value) || null;
return s;
});
}
return application;
}
}
const staticApps = ["static", "react", "vuejs", "svelte", "gatsby", "astro", "eleventy"];
const nodeBased = [
"react",
"preact",
"vuejs",
"svelte",
"gatsby",
"astro",
"eleventy",
"node",
"nestjs",
"nuxtjs",
"nextjs"
];
function setDefaultBaseImage(buildPack, deploymentType = null) {
const nodeVersions = [
{
value: "node:lts",
label: "node:lts"
},
{
value: "node:18",
label: "node:18"
},
{
value: "node:17",
label: "node:17"
},
{
value: "node:16",
label: "node:16"
},
{
value: "node:14",
label: "node:14"
},
{
value: "node:12",
label: "node:12"
}
];
const staticVersions = [
{
value: "webdevops/nginx:alpine",
label: "webdevops/nginx:alpine"
},
{
value: "webdevops/apache:alpine",
label: "webdevops/apache:alpine"
},
{
value: "nginx:alpine",
label: "nginx:alpine"
},
{
value: "httpd:alpine",
label: "httpd:alpine (Apache)"
}
];
const rustVersions = [
{
value: "rust:latest",
label: "rust:latest"
},
{
value: "rust:1.60",
label: "rust:1.60"
},
{
value: "rust:1.60-buster",
label: "rust:1.60-buster"
},
{
value: "rust:1.60-bullseye",
label: "rust:1.60-bullseye"
},
{
value: "rust:1.60-slim-buster",
label: "rust:1.60-slim-buster"
},
{
value: "rust:1.60-slim-bullseye",
label: "rust:1.60-slim-bullseye"
},
{
value: "rust:1.60-alpine3.14",
label: "rust:1.60-alpine3.14"
},
{
value: "rust:1.60-alpine3.15",
label: "rust:1.60-alpine3.15"
}
];
const phpVersions = [
{
value: "webdevops/php-apache:8.2",
label: "webdevops/php-apache:8.2"
},
{
value: "webdevops/php-nginx:8.2",
label: "webdevops/php-nginx:8.2"
},
{
value: "webdevops/php-apache:8.1",
label: "webdevops/php-apache:8.1"
},
{
value: "webdevops/php-nginx:8.1",
label: "webdevops/php-nginx:8.1"
},
{
value: "webdevops/php-apache:8.0",
label: "webdevops/php-apache:8.0"
},
{
value: "webdevops/php-nginx:8.0",
label: "webdevops/php-nginx:8.0"
},
{
value: "webdevops/php-apache:7.4",
label: "webdevops/php-apache:7.4"
},
{
value: "webdevops/php-nginx:7.4",
label: "webdevops/php-nginx:7.4"
},
{
value: "webdevops/php-apache:7.3",
label: "webdevops/php-apache:7.3"
},
{
value: "webdevops/php-nginx:7.3",
label: "webdevops/php-nginx:7.3"
},
{
value: "webdevops/php-apache:7.2",
label: "webdevops/php-apache:7.2"
},
{
value: "webdevops/php-nginx:7.2",
label: "webdevops/php-nginx:7.2"
},
{
value: "webdevops/php-apache:7.1",
label: "webdevops/php-apache:7.1"
},
{
value: "webdevops/php-nginx:7.1",
label: "webdevops/php-nginx:7.1"
},
{
value: "webdevops/php-apache:7.0",
label: "webdevops/php-apache:7.0"
},
{
value: "webdevops/php-nginx:7.0",
label: "webdevops/php-nginx:7.0"
},
{
value: "webdevops/php-apache:5.6",
label: "webdevops/php-apache:5.6"
},
{
value: "webdevops/php-nginx:5.6",
label: "webdevops/php-nginx:5.6"
},
{
value: "webdevops/php-apache:8.2-alpine",
label: "webdevops/php-apache:8.2-alpine"
},
{
value: "webdevops/php-nginx:8.2-alpine",
label: "webdevops/php-nginx:8.2-alpine"
},
{
value: "webdevops/php-apache:8.1-alpine",
label: "webdevops/php-apache:8.1-alpine"
},
{
value: "webdevops/php-nginx:8.1-alpine",
label: "webdevops/php-nginx:8.1-alpine"
},
{
value: "webdevops/php-apache:8.0-alpine",
label: "webdevops/php-apache:8.0-alpine"
},
{
value: "webdevops/php-nginx:8.0-alpine",
label: "webdevops/php-nginx:8.0-alpine"
},
{
value: "webdevops/php-apache:7.4-alpine",
label: "webdevops/php-apache:7.4-alpine"
},
{
value: "webdevops/php-nginx:7.4-alpine",
label: "webdevops/php-nginx:7.4-alpine"
},
{
value: "webdevops/php-apache:7.3-alpine",
label: "webdevops/php-apache:7.3-alpine"
},
{
value: "webdevops/php-nginx:7.3-alpine",
label: "webdevops/php-nginx:7.3-alpine"
},
{
value: "webdevops/php-apache:7.2-alpine",
label: "webdevops/php-apache:7.2-alpine"
},
{
value: "webdevops/php-nginx:7.2-alpine",
label: "webdevops/php-nginx:7.2-alpine"
},
{
value: "webdevops/php-apache:7.1-alpine",
label: "webdevops/php-apache:7.1-alpine"
},
{
value: "php:8.1-fpm",
label: "php:8.1-fpm"
},
{
value: "php:8.0-fpm",
label: "php:8.0-fpm"
},
{
value: "php:8.1-fpm-alpine",
label: "php:8.1-fpm-alpine"
},
{
value: "php:8.0-fpm-alpine",
label: "php:8.0-fpm-alpine"
}
];
const pythonVersions = [
{
value: "python:3.10-alpine",
label: "python:3.10-alpine"
},
{
value: "python:3.10-buster",
label: "python:3.10-buster"
},
{
value: "python:3.10-bullseye",
label: "python:3.10-bullseye"
},
{
value: "python:3.10-slim-bullseye",
label: "python:3.10-slim-bullseye"
},
{
value: "python:3.9-alpine",
label: "python:3.9-alpine"
},
{
value: "python:3.9-buster",
label: "python:3.9-buster"
},
{
value: "python:3.9-bullseye",
label: "python:3.9-bullseye"
},
{
value: "python:3.9-slim-bullseye",
label: "python:3.9-slim-bullseye"
},
{
value: "python:3.8-alpine",
label: "python:3.8-alpine"
},
{
value: "python:3.8-buster",
label: "python:3.8-buster"
},
{
value: "python:3.8-bullseye",
label: "python:3.8-bullseye"
},
{
value: "python:3.8-slim-bullseye",
label: "python:3.8-slim-bullseye"
},
{
value: "python:3.7-alpine",
label: "python:3.7-alpine"
},
{
value: "python:3.7-buster",
label: "python:3.7-buster"
},
{
value: "python:3.7-bullseye",
label: "python:3.7-bullseye"
},
{
value: "python:3.7-slim-bullseye",
label: "python:3.7-slim-bullseye"
}
];
const herokuVersions = [
{
value: "heroku/builder:22",
label: "heroku/builder:22"
},
{
value: "heroku/buildpacks:20",
label: "heroku/buildpacks:20"
},
{
value: "heroku/builder-classic:22",
label: "heroku/builder-classic:22"
}
];
let payload = {
baseImage: null,
baseBuildImage: null,
baseImages: [],
baseBuildImages: []
};
if (nodeBased.includes(buildPack)) {
if (deploymentType === "static") {
payload.baseImage = (0, import_common.isARM)(process.arch) ? "nginx:alpine" : "webdevops/nginx:alpine";
payload.baseImages = (0, import_common.isARM)(process.arch) ? staticVersions.filter((version) => !version.value.includes("webdevops")) : staticVersions;
payload.baseBuildImage = "node:lts";
payload.baseBuildImages = nodeVersions;
} else {
payload.baseImage = "node:lts";
payload.baseImages = nodeVersions;
payload.baseBuildImage = "node:lts";
payload.baseBuildImages = nodeVersions;
}
}
if (staticApps.includes(buildPack)) {
payload.baseImage = (0, import_common.isARM)(process.arch) ? "nginx:alpine" : "webdevops/nginx:alpine";
payload.baseImages = (0, import_common.isARM)(process.arch) ? staticVersions.filter((version) => !version.value.includes("webdevops")) : staticVersions;
payload.baseBuildImage = "node:lts";
payload.baseBuildImages = nodeVersions;
}
if (buildPack === "python") {
payload.baseImage = "python:3.10-alpine";
payload.baseImages = pythonVersions;
}
if (buildPack === "rust") {
payload.baseImage = "rust:latest";
payload.baseBuildImage = "rust:latest";
payload.baseImages = rustVersions;
payload.baseBuildImages = rustVersions;
}
if (buildPack === "deno") {
payload.baseImage = "denoland/deno:latest";
}
if (buildPack === "php") {
payload.baseImage = (0, import_common.isARM)(process.arch) ? "php:8.1-fpm-alpine" : "webdevops/php-apache:8.2-alpine";
payload.baseImages = (0, import_common.isARM)(process.arch) ? phpVersions.filter((version) => !version.value.includes("webdevops")) : phpVersions;
}
if (buildPack === "laravel") {
payload.baseImage = (0, import_common.isARM)(process.arch) ? "php:8.1-fpm-alpine" : "webdevops/php-apache:8.2-alpine";
payload.baseImages = (0, import_common.isARM)(process.arch) ? phpVersions.filter((version) => !version.value.includes("webdevops")) : phpVersions;
payload.baseBuildImage = "node:18";
payload.baseBuildImages = nodeVersions;
}
if (buildPack === "heroku") {
payload.baseImage = "heroku/buildpacks:20";
payload.baseImages = herokuVersions;
}
return payload;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
deployApplication,
generateConfigHash,
getApplicationFromDB,
setDefaultBaseImage
});

View File

@@ -0,0 +1,201 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var auth_exports = {};
__export(auth_exports, {
authRouter: () => authRouter
});
module.exports = __toCommonJS(auth_exports);
var import_zod = require("zod");
var import_trpc = require("../trpc");
var import_server = require("@trpc/server");
var import_common = require("../../lib/common");
var import_env = require("../../env");
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
var import_prisma = require("../../prisma");
var import_cuid = __toESM(require("cuid"));
const authRouter = (0, import_trpc.router)({
register: import_trpc.publicProcedure.input(
import_zod.z.object({
email: import_zod.z.string(),
password: import_zod.z.string()
})
).mutation(async ({ input }) => {
const { email, password } = input;
const userFound = await import_prisma.prisma.user.findUnique({
where: { email },
include: { teams: true, permission: true }
});
if (userFound) {
throw new import_server.TRPCError({
code: "BAD_REQUEST",
message: "User already exists."
});
}
const settings = await (0, import_common.listSettings)();
if (!settings?.isRegistrationEnabled) {
throw new import_server.TRPCError({
code: "FORBIDDEN",
message: "Registration is disabled."
});
}
const usersCount = await import_prisma.prisma.user.count();
const uid = usersCount === 0 ? "0" : (0, import_cuid.default)();
const permission = "owner";
const isAdmin = true;
const hashedPassword = await (0, import_common.hashPassword)(password);
if (usersCount === 0) {
await import_prisma.prisma.user.create({
data: {
id: uid,
email,
password: hashedPassword,
type: "email",
teams: {
create: {
id: uid,
name: (0, import_common.uniqueName)(),
destinationDocker: { connect: { network: "coolify" } }
}
},
permission: { create: { teamId: uid, permission } }
},
include: { teams: true }
});
await import_prisma.prisma.setting.update({
where: { id: "0" },
data: { isRegistrationEnabled: false }
});
} else {
await import_prisma.prisma.user.create({
data: {
id: uid,
email,
password: hashedPassword,
type: "email",
teams: {
create: {
id: uid,
name: (0, import_common.uniqueName)()
}
},
permission: { create: { teamId: uid, permission } }
},
include: { teams: true }
});
}
const payload = {
userId: uid,
teamId: uid,
permission,
isAdmin
};
return {
...payload,
token: import_jsonwebtoken.default.sign(payload, import_env.env.COOLIFY_SECRET_KEY)
};
}),
login: import_trpc.publicProcedure.input(
import_zod.z.object({
email: import_zod.z.string(),
password: import_zod.z.string()
})
).mutation(async ({ input }) => {
const { email, password } = input;
const userFound = await import_prisma.prisma.user.findUnique({
where: { email },
include: { teams: true, permission: true }
});
if (!userFound) {
throw new import_server.TRPCError({
code: "BAD_REQUEST",
message: "User already exists."
});
}
if (userFound.type === "email") {
if (userFound.password === "RESETME") {
const hashedPassword = await (0, import_common.hashPassword)(password);
if (userFound.updatedAt < new Date(Date.now() - 1e3 * 60 * 10)) {
if (userFound.id === "0") {
await import_prisma.prisma.user.update({
where: { email: userFound.email },
data: { password: "RESETME" }
});
} else {
await import_prisma.prisma.user.update({
where: { email: userFound.email },
data: { password: "RESETTIMEOUT" }
});
}
} else {
await import_prisma.prisma.user.update({
where: { email: userFound.email },
data: { password: hashedPassword }
});
const payload2 = {
userId: userFound.id,
teamId: userFound.id,
permission: userFound.permission,
isAdmin: true
};
return {
...payload2,
token: import_jsonwebtoken.default.sign(payload2, import_env.env.COOLIFY_SECRET_KEY)
};
}
}
if (!userFound.password) {
throw new import_server.TRPCError({
code: "BAD_REQUEST",
message: "Something went wrong. Please try again later."
});
}
const passwordMatch = (0, import_common.comparePassword)(password, userFound.password);
if (!passwordMatch) {
throw new import_server.TRPCError({
code: "BAD_REQUEST",
message: "Incorrect password."
});
}
const payload = {
userId: userFound.id,
teamId: userFound.id,
permission: userFound.permission,
isAdmin: true
};
return {
...payload,
token: import_jsonwebtoken.default.sign(payload, import_env.env.COOLIFY_SECRET_KEY)
};
}
throw new import_server.TRPCError({
code: "BAD_REQUEST",
message: "Not implemented yet."
});
})
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
authRouter
});

View File

@@ -0,0 +1,87 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var dashboard_exports = {};
__export(dashboard_exports, {
dashboardRouter: () => dashboardRouter
});
module.exports = __toCommonJS(dashboard_exports);
var import_trpc = require("../trpc");
var import_common = require("../../lib/common");
var import_prisma = require("../../prisma");
const dashboardRouter = (0, import_trpc.router)({
resources: import_trpc.privateProcedure.query(async ({ ctx }) => {
const id = ctx.user?.teamId === "0" ? void 0 : ctx.user?.teamId;
let applications = await import_prisma.prisma.application.findMany({
where: { teams: { some: { id } } },
include: { settings: true, destinationDocker: true, teams: true }
});
const databases = await import_prisma.prisma.database.findMany({
where: { teams: { some: { id } } },
include: { settings: true, destinationDocker: true, teams: true }
});
const services = await import_prisma.prisma.service.findMany({
where: { teams: { some: { id } } },
include: { destinationDocker: true, teams: true }
});
const gitSources = await import_prisma.prisma.gitSource.findMany({
where: {
OR: [{ teams: { some: { id } } }, { isSystemWide: true }]
},
include: { teams: true }
});
const destinations = await import_prisma.prisma.destinationDocker.findMany({
where: { teams: { some: { id } } },
include: { teams: true }
});
const settings = await (0, import_common.listSettings)();
let foundUnconfiguredApplication = false;
for (const application of applications) {
if ((!application.buildPack || !application.branch) && !application.simpleDockerfile || !application.destinationDockerId || !application.settings?.isBot && !application?.fqdn && application.buildPack !== "compose") {
foundUnconfiguredApplication = true;
}
}
let foundUnconfiguredService = false;
for (const service of services) {
if (!service.fqdn) {
foundUnconfiguredService = true;
}
}
let foundUnconfiguredDatabase = false;
for (const database of databases) {
if (!database.version) {
foundUnconfiguredDatabase = true;
}
}
return {
foundUnconfiguredApplication,
foundUnconfiguredDatabase,
foundUnconfiguredService,
applications,
databases,
services,
gitSources,
destinations,
settings
};
})
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
dashboardRouter
});

View File

@@ -0,0 +1,384 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var databases_exports = {};
__export(databases_exports, {
databasesRouter: () => databasesRouter
});
module.exports = __toCommonJS(databases_exports);
var import_zod = require("zod");
var import_promises = __toESM(require("fs/promises"));
var import_trpc = require("../../trpc");
var import_common = require("../../../lib/common");
var import_prisma = require("../../../prisma");
var import_executeCommand = require("../../../lib/executeCommand");
var import_docker = require("../../../lib/docker");
var import_lib = require("./lib");
var import_js_yaml = __toESM(require("js-yaml"));
var import_lib2 = require("../services/lib");
const databasesRouter = (0, import_trpc.router)({
usage: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string()
})
).query(async ({ ctx, input }) => {
const teamId = ctx.user?.teamId;
const { id } = input;
let usage = {};
const database = await import_prisma.prisma.database.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { destinationDocker: true, settings: true }
});
if (database.dbUserPassword)
database.dbUserPassword = (0, import_common.decrypt)(database.dbUserPassword);
if (database.rootUserPassword)
database.rootUserPassword = (0, import_common.decrypt)(database.rootUserPassword);
if (database.destinationDockerId) {
[usage] = await Promise.all([(0, import_common.getContainerUsage)(database.destinationDocker.id, id)]);
}
return {
success: true,
data: {
usage
}
};
}),
save: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string()
})
).mutation(async ({ ctx, input }) => {
const teamId = ctx.user?.teamId;
const {
id,
name,
defaultDatabase,
dbUser,
dbUserPassword,
rootUser,
rootUserPassword,
version,
isRunning
} = input;
const database = await import_prisma.prisma.database.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { destinationDocker: true, settings: true }
});
if (database.dbUserPassword)
database.dbUserPassword = (0, import_common.decrypt)(database.dbUserPassword);
if (database.rootUserPassword)
database.rootUserPassword = (0, import_common.decrypt)(database.rootUserPassword);
if (isRunning) {
if (database.dbUserPassword !== dbUserPassword) {
await (0, import_lib.updatePasswordInDb)(database, dbUser, dbUserPassword, false);
} else if (database.rootUserPassword !== rootUserPassword) {
await (0, import_lib.updatePasswordInDb)(database, rootUser, rootUserPassword, true);
}
}
const encryptedDbUserPassword = dbUserPassword && (0, import_common.encrypt)(dbUserPassword);
const encryptedRootUserPassword = rootUserPassword && (0, import_common.encrypt)(rootUserPassword);
await import_prisma.prisma.database.update({
where: { id },
data: {
name,
defaultDatabase,
dbUser,
dbUserPassword: encryptedDbUserPassword,
rootUser,
rootUserPassword: encryptedRootUserPassword,
version
}
});
}),
saveSettings: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
isPublic: import_zod.z.boolean(),
appendOnly: import_zod.z.boolean().default(true)
})
).mutation(async ({ ctx, input }) => {
const teamId = ctx.user?.teamId;
const { id, isPublic, appendOnly = true } = input;
let publicPort = null;
const {
destinationDocker: { remoteEngine, engine, remoteIpAddress }
} = await import_prisma.prisma.database.findUnique({ where: { id }, include: { destinationDocker: true } });
if (isPublic) {
publicPort = await (0, import_lib2.getFreePublicPort)({ id, remoteEngine, engine, remoteIpAddress });
}
await import_prisma.prisma.database.update({
where: { id },
data: {
settings: {
upsert: { update: { isPublic, appendOnly }, create: { isPublic, appendOnly } }
}
}
});
const database = await import_prisma.prisma.database.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { destinationDocker: true, settings: true }
});
const { arch } = await (0, import_common.listSettings)();
if (database.dbUserPassword)
database.dbUserPassword = (0, import_common.decrypt)(database.dbUserPassword);
if (database.rootUserPassword)
database.rootUserPassword = (0, import_common.decrypt)(database.rootUserPassword);
const { destinationDockerId, destinationDocker, publicPort: oldPublicPort } = database;
const { privatePort } = (0, import_lib.generateDatabaseConfiguration)(database, arch);
if (destinationDockerId) {
if (isPublic) {
await import_prisma.prisma.database.update({ where: { id }, data: { publicPort } });
await (0, import_common.startTraefikTCPProxy)(destinationDocker, id, publicPort, privatePort);
} else {
await import_prisma.prisma.database.update({ where: { id }, data: { publicPort: null } });
await (0, import_docker.stopTcpHttpProxy)(id, destinationDocker, oldPublicPort);
}
}
return { publicPort };
}),
saveSecret: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
name: import_zod.z.string(),
value: import_zod.z.string(),
isNew: import_zod.z.boolean().default(true)
})
).mutation(async ({ ctx, input }) => {
let { id, name, value, isNew } = input;
if (isNew) {
const found = await import_prisma.prisma.databaseSecret.findFirst({ where: { name, databaseId: id } });
if (found) {
throw `Secret ${name} already exists.`;
} else {
value = (0, import_common.encrypt)(value.trim());
await import_prisma.prisma.databaseSecret.create({
data: { name, value, database: { connect: { id } } }
});
}
} else {
value = (0, import_common.encrypt)(value.trim());
const found = await import_prisma.prisma.databaseSecret.findFirst({ where: { databaseId: id, name } });
if (found) {
await import_prisma.prisma.databaseSecret.updateMany({
where: { databaseId: id, name },
data: { value }
});
} else {
await import_prisma.prisma.databaseSecret.create({
data: { name, value, database: { connect: { id } } }
});
}
}
}),
start: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).mutation(async ({ ctx, input }) => {
const { id } = input;
const teamId = ctx.user?.teamId;
const database = await import_prisma.prisma.database.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { destinationDocker: true, settings: true, databaseSecret: true }
});
const { arch } = await (0, import_common.listSettings)();
if (database.dbUserPassword)
database.dbUserPassword = (0, import_common.decrypt)(database.dbUserPassword);
if (database.rootUserPassword)
database.rootUserPassword = (0, import_common.decrypt)(database.rootUserPassword);
const {
type,
destinationDockerId,
destinationDocker,
publicPort,
settings: { isPublic },
databaseSecret
} = database;
const { privatePort, command, environmentVariables, image, volume, ulimits } = (0, import_lib.generateDatabaseConfiguration)(database, arch);
const network = destinationDockerId && destinationDocker.network;
const volumeName = volume.split(":")[0];
const labels = await (0, import_lib.makeLabelForStandaloneDatabase)({ id, image, volume });
const { workdir } = await (0, import_common.createDirectories)({ repository: type, buildId: id });
if (databaseSecret.length > 0) {
databaseSecret.forEach((secret) => {
environmentVariables[secret.name] = (0, import_common.decrypt)(secret.value);
});
}
const composeFile = {
version: "3.8",
services: {
[id]: {
container_name: id,
image,
command,
environment: environmentVariables,
volumes: [volume],
ulimits,
labels,
...(0, import_docker.defaultComposeConfiguration)(network)
}
},
networks: {
[network]: {
external: true
}
},
volumes: {
[volumeName]: {
name: volumeName
}
}
};
const composeFileDestination = `${workdir}/docker-compose.yaml`;
await import_promises.default.writeFile(composeFileDestination, import_js_yaml.default.dump(composeFile));
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDocker.id,
command: `docker compose -f ${composeFileDestination} up -d`
});
if (isPublic)
await (0, import_common.startTraefikTCPProxy)(destinationDocker, id, publicPort, privatePort);
}),
stop: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).mutation(async ({ ctx, input }) => {
const { id } = input;
const teamId = ctx.user?.teamId;
const database = await import_prisma.prisma.database.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { destinationDocker: true, settings: true }
});
if (database.dbUserPassword)
database.dbUserPassword = (0, import_common.decrypt)(database.dbUserPassword);
if (database.rootUserPassword)
database.rootUserPassword = (0, import_common.decrypt)(database.rootUserPassword);
const everStarted = await (0, import_docker.stopDatabaseContainer)(database);
if (everStarted)
await (0, import_docker.stopTcpHttpProxy)(id, database.destinationDocker, database.publicPort);
await import_prisma.prisma.database.update({
where: { id },
data: {
settings: { upsert: { update: { isPublic: false }, create: { isPublic: false } } }
}
});
await import_prisma.prisma.database.update({ where: { id }, data: { publicPort: null } });
}),
getDatabaseById: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).query(async ({ ctx, input }) => {
const { id } = input;
const teamId = ctx.user?.teamId;
const database = await import_prisma.prisma.database.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { destinationDocker: true, settings: true }
});
if (!database) {
throw { status: 404, message: "Database not found." };
}
const settings = await (0, import_common.listSettings)();
if (database.dbUserPassword)
database.dbUserPassword = (0, import_common.decrypt)(database.dbUserPassword);
if (database.rootUserPassword)
database.rootUserPassword = (0, import_common.decrypt)(database.rootUserPassword);
const configuration = (0, import_lib.generateDatabaseConfiguration)(database, settings.arch);
return {
success: true,
data: {
privatePort: configuration?.privatePort,
database,
versions: await (0, import_lib.getDatabaseVersions)(database.type, settings.arch),
settings
}
};
}),
status: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).query(async ({ ctx, input }) => {
const id = input.id;
const teamId = ctx.user?.teamId;
let isRunning = false;
const database = await import_prisma.prisma.database.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { destinationDocker: true, settings: true }
});
if (database) {
const { destinationDockerId, destinationDocker } = database;
if (destinationDockerId) {
try {
const { stdout } = await (0, import_executeCommand.executeCommand)({
dockerId: destinationDocker.id,
command: `docker inspect --format '{{json .State}}' ${id}`
});
if (JSON.parse(stdout).Running) {
isRunning = true;
}
} catch (error) {
}
}
}
return {
success: true,
data: {
isRunning
}
};
}),
cleanup: import_trpc.privateProcedure.query(async ({ ctx }) => {
const teamId = ctx.user?.teamId;
let databases = await import_prisma.prisma.database.findMany({
where: { teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { settings: true, destinationDocker: true, teams: true }
});
for (const database of databases) {
if (!database?.version) {
const { id } = database;
if (database.destinationDockerId) {
const everStarted = await (0, import_docker.stopDatabaseContainer)(database);
if (everStarted)
await (0, import_docker.stopTcpHttpProxy)(id, database.destinationDocker, database.publicPort);
}
await import_prisma.prisma.databaseSettings.deleteMany({ where: { databaseId: id } });
await import_prisma.prisma.databaseSecret.deleteMany({ where: { databaseId: id } });
await import_prisma.prisma.database.delete({ where: { id } });
}
}
return {};
}),
delete: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string(), force: import_zod.z.boolean().default(false) })).mutation(async ({ ctx, input }) => {
const { id, force } = input;
const teamId = ctx.user?.teamId;
const database = await import_prisma.prisma.database.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { destinationDocker: true, settings: true }
});
if (!force) {
if (database.dbUserPassword)
database.dbUserPassword = (0, import_common.decrypt)(database.dbUserPassword);
if (database.rootUserPassword)
database.rootUserPassword = (0, import_common.decrypt)(database.rootUserPassword);
if (database.destinationDockerId) {
const everStarted = await (0, import_docker.stopDatabaseContainer)(database);
if (everStarted)
await (0, import_docker.stopTcpHttpProxy)(id, database.destinationDocker, database.publicPort);
}
}
await import_prisma.prisma.databaseSettings.deleteMany({ where: { databaseId: id } });
await import_prisma.prisma.databaseSecret.deleteMany({ where: { databaseId: id } });
await import_prisma.prisma.database.delete({ where: { id } });
return {};
})
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
databasesRouter
});

View File

@@ -0,0 +1,316 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var lib_exports = {};
__export(lib_exports, {
generateDatabaseConfiguration: () => generateDatabaseConfiguration,
getDatabaseImage: () => getDatabaseImage,
getDatabaseVersions: () => getDatabaseVersions,
makeLabelForStandaloneDatabase: () => makeLabelForStandaloneDatabase,
supportedDatabaseTypesAndVersions: () => supportedDatabaseTypesAndVersions,
updatePasswordInDb: () => updatePasswordInDb
});
module.exports = __toCommonJS(lib_exports);
var import_common = require("../../../lib/common");
var import_executeCommand = require("../../../lib/executeCommand");
var import_prisma = require("../../../prisma");
const supportedDatabaseTypesAndVersions = [
{
name: "mongodb",
fancyName: "MongoDB",
baseImage: "bitnami/mongodb",
baseImageARM: "mongo",
versions: ["5.0", "4.4", "4.2"],
versionsARM: ["5.0", "4.4", "4.2"]
},
{
name: "mysql",
fancyName: "MySQL",
baseImage: "bitnami/mysql",
baseImageARM: "mysql",
versions: ["8.0", "5.7"],
versionsARM: ["8.0", "5.7"]
},
{
name: "mariadb",
fancyName: "MariaDB",
baseImage: "bitnami/mariadb",
baseImageARM: "mariadb",
versions: ["10.8", "10.7", "10.6", "10.5", "10.4", "10.3", "10.2"],
versionsARM: ["10.8", "10.7", "10.6", "10.5", "10.4", "10.3", "10.2"]
},
{
name: "postgresql",
fancyName: "PostgreSQL",
baseImage: "bitnami/postgresql",
baseImageARM: "postgres",
versions: ["14.5.0", "13.8.0", "12.12.0", "11.17.0", "10.22.0"],
versionsARM: ["14.5", "13.8", "12.12", "11.17", "10.22"]
},
{
name: "redis",
fancyName: "Redis",
baseImage: "bitnami/redis",
baseImageARM: "redis",
versions: ["7.0", "6.2", "6.0", "5.0"],
versionsARM: ["7.0", "6.2", "6.0", "5.0"]
},
{
name: "couchdb",
fancyName: "CouchDB",
baseImage: "bitnami/couchdb",
baseImageARM: "couchdb",
versions: ["3.2.2", "3.1.2", "2.3.1"],
versionsARM: ["3.2.2", "3.1.2", "2.3.1"]
},
{
name: "edgedb",
fancyName: "EdgeDB",
baseImage: "edgedb/edgedb",
versions: ["latest", "2.1", "2.0", "1.4"]
}
];
function getDatabaseImage(type, arch) {
const found = supportedDatabaseTypesAndVersions.find((t) => t.name === type);
if (found) {
if ((0, import_common.isARM)(arch)) {
return found.baseImageARM || found.baseImage;
}
return found.baseImage;
}
return "";
}
function generateDatabaseConfiguration(database, arch) {
const { id, dbUser, dbUserPassword, rootUser, rootUserPassword, defaultDatabase, version: version2, type } = database;
const baseImage = getDatabaseImage(type, arch);
if (type === "mysql") {
const configuration = {
privatePort: 3306,
environmentVariables: {
MYSQL_USER: dbUser,
MYSQL_PASSWORD: dbUserPassword,
MYSQL_ROOT_PASSWORD: rootUserPassword,
MYSQL_ROOT_USER: rootUser,
MYSQL_DATABASE: defaultDatabase
},
image: `${baseImage}:${version2}`,
volume: `${id}-${type}-data:/bitnami/mysql/data`,
ulimits: {}
};
if ((0, import_common.isARM)(arch)) {
configuration.volume = `${id}-${type}-data:/var/lib/mysql`;
}
return configuration;
} else if (type === "mariadb") {
const configuration = {
privatePort: 3306,
environmentVariables: {
MARIADB_ROOT_USER: rootUser,
MARIADB_ROOT_PASSWORD: rootUserPassword,
MARIADB_USER: dbUser,
MARIADB_PASSWORD: dbUserPassword,
MARIADB_DATABASE: defaultDatabase
},
image: `${baseImage}:${version2}`,
volume: `${id}-${type}-data:/bitnami/mariadb`,
ulimits: {}
};
if ((0, import_common.isARM)(arch)) {
configuration.volume = `${id}-${type}-data:/var/lib/mysql`;
}
return configuration;
} else if (type === "mongodb") {
const configuration = {
privatePort: 27017,
environmentVariables: {
MONGODB_ROOT_USER: rootUser,
MONGODB_ROOT_PASSWORD: rootUserPassword
},
image: `${baseImage}:${version2}`,
volume: `${id}-${type}-data:/bitnami/mongodb`,
ulimits: {}
};
if ((0, import_common.isARM)(arch)) {
configuration.environmentVariables = {
MONGO_INITDB_ROOT_USERNAME: rootUser,
MONGO_INITDB_ROOT_PASSWORD: rootUserPassword
};
configuration.volume = `${id}-${type}-data:/data/db`;
}
return configuration;
} else if (type === "postgresql") {
const configuration = {
privatePort: 5432,
environmentVariables: {
POSTGRESQL_POSTGRES_PASSWORD: rootUserPassword,
POSTGRESQL_PASSWORD: dbUserPassword,
POSTGRESQL_USERNAME: dbUser,
POSTGRESQL_DATABASE: defaultDatabase
},
image: `${baseImage}:${version2}`,
volume: `${id}-${type}-data:/bitnami/postgresql`,
ulimits: {}
};
if ((0, import_common.isARM)(arch)) {
configuration.volume = `${id}-${type}-data:/var/lib/postgresql`;
configuration.environmentVariables = {
POSTGRES_PASSWORD: dbUserPassword,
POSTGRES_USER: dbUser,
POSTGRES_DB: defaultDatabase
};
}
return configuration;
} else if (type === "redis") {
const {
settings: { appendOnly }
} = database;
const configuration = {
privatePort: 6379,
command: void 0,
environmentVariables: {
REDIS_PASSWORD: dbUserPassword,
REDIS_AOF_ENABLED: appendOnly ? "yes" : "no"
},
image: `${baseImage}:${version2}`,
volume: `${id}-${type}-data:/bitnami/redis/data`,
ulimits: {}
};
if ((0, import_common.isARM)(arch)) {
configuration.volume = `${id}-${type}-data:/data`;
configuration.command = `/usr/local/bin/redis-server --appendonly ${appendOnly ? "yes" : "no"} --requirepass ${dbUserPassword}`;
}
return configuration;
} else if (type === "couchdb") {
const configuration = {
privatePort: 5984,
environmentVariables: {
COUCHDB_PASSWORD: dbUserPassword,
COUCHDB_USER: dbUser
},
image: `${baseImage}:${version2}`,
volume: `${id}-${type}-data:/bitnami/couchdb`,
ulimits: {}
};
if ((0, import_common.isARM)(arch)) {
configuration.volume = `${id}-${type}-data:/opt/couchdb/data`;
}
return configuration;
} else if (type === "edgedb") {
const configuration = {
privatePort: 5656,
environmentVariables: {
EDGEDB_SERVER_PASSWORD: rootUserPassword,
EDGEDB_SERVER_USER: rootUser,
EDGEDB_SERVER_DATABASE: defaultDatabase,
EDGEDB_SERVER_TLS_CERT_MODE: "generate_self_signed"
},
image: `${baseImage}:${version2}`,
volume: `${id}-${type}-data:/var/lib/edgedb/data`,
ulimits: {}
};
return configuration;
}
return null;
}
function getDatabaseVersions(type, arch) {
const found = supportedDatabaseTypesAndVersions.find((t) => t.name === type);
if (found) {
if ((0, import_common.isARM)(arch)) {
return found.versionsARM || found.versions;
}
return found.versions;
}
return [];
}
async function updatePasswordInDb(database, user, newPassword, isRoot) {
const {
id,
type,
rootUser,
rootUserPassword,
dbUser,
dbUserPassword,
defaultDatabase,
destinationDockerId,
destinationDocker: { id: dockerId }
} = database;
if (destinationDockerId) {
if (type === "mysql") {
await (0, import_executeCommand.executeCommand)({
dockerId,
command: `docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e "ALTER USER '${user}'@'%' IDENTIFIED WITH caching_sha2_password BY '${newPassword}';"`
});
} else if (type === "mariadb") {
await (0, import_executeCommand.executeCommand)({
dockerId,
command: `docker exec ${id} mysql -u ${rootUser} -p${rootUserPassword} -e "SET PASSWORD FOR '${user}'@'%' = PASSWORD('${newPassword}');"`
});
} else if (type === "postgresql") {
if (isRoot) {
await (0, import_executeCommand.executeCommand)({
dockerId,
command: `docker exec ${id} psql postgresql://postgres:${rootUserPassword}@${id}:5432/${defaultDatabase} -c "ALTER role postgres WITH PASSWORD '${newPassword}'"`
});
} else {
await (0, import_executeCommand.executeCommand)({
dockerId,
command: `docker exec ${id} psql postgresql://${dbUser}:${dbUserPassword}@${id}:5432/${defaultDatabase} -c "ALTER role ${user} WITH PASSWORD '${newPassword}'"`
});
}
} else if (type === "mongodb") {
await (0, import_executeCommand.executeCommand)({
dockerId,
command: `docker exec ${id} mongo 'mongodb://${rootUser}:${rootUserPassword}@${id}:27017/admin?readPreference=primary&ssl=false' --eval "db.changeUserPassword('${user}','${newPassword}')"`
});
} else if (type === "redis") {
await (0, import_executeCommand.executeCommand)({
dockerId,
command: `docker exec ${id} redis-cli -u redis://${dbUserPassword}@${id}:6379 --raw CONFIG SET requirepass ${newPassword}`
});
}
}
}
async function makeLabelForStandaloneDatabase({ id, image, volume }) {
const database = await import_prisma.prisma.database.findFirst({ where: { id } });
delete database.destinationDockerId;
delete database.createdAt;
delete database.updatedAt;
return [
"coolify.managed=true",
`coolify.version=${import_common.version}`,
`coolify.type=standalone-database`,
`coolify.name=${database.name}`,
`coolify.configuration=${(0, import_common.base64Encode)(
JSON.stringify({
version: import_common.version,
image,
volume,
...database
})
)}`
];
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
generateDatabaseConfiguration,
getDatabaseImage,
getDatabaseVersions,
makeLabelForStandaloneDatabase,
supportedDatabaseTypesAndVersions,
updatePasswordInDb
});

View File

@@ -0,0 +1,220 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var destinations_exports = {};
__export(destinations_exports, {
destinationsRouter: () => destinationsRouter
});
module.exports = __toCommonJS(destinations_exports);
var import_zod = require("zod");
var import_trpc = require("../../trpc");
var import_common = require("../../../lib/common");
var import_prisma = require("../../../prisma");
var import_executeCommand = require("../../../lib/executeCommand");
var import_docker = require("../../../lib/docker");
const destinationsRouter = (0, import_trpc.router)({
restartProxy: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string()
})
).mutation(async ({ input, ctx }) => {
const { id } = input;
await (0, import_common.stopTraefikProxy)(id);
await (0, import_common.startTraefikProxy)(id);
await import_prisma.prisma.destinationDocker.update({
where: { id },
data: { isCoolifyProxyUsed: true }
});
}),
startProxy: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string()
})
).mutation(async ({ input, ctx }) => {
const { id } = input;
await (0, import_common.startTraefikProxy)(id);
}),
stopProxy: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string()
})
).mutation(async ({ input, ctx }) => {
const { id } = input;
await (0, import_common.stopTraefikProxy)(id);
}),
saveSettings: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
engine: import_zod.z.string(),
isCoolifyProxyUsed: import_zod.z.boolean()
})
).mutation(async ({ input, ctx }) => {
const { id, engine, isCoolifyProxyUsed } = input;
await import_prisma.prisma.destinationDocker.updateMany({
where: { engine },
data: { isCoolifyProxyUsed }
});
}),
status: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).query(async ({ input, ctx }) => {
const { id } = input;
const destination = await import_prisma.prisma.destinationDocker.findUnique({ where: { id } });
const { found: isRunning } = await (0, import_docker.checkContainer)({
dockerId: destination.id,
container: "coolify-proxy",
remove: true
});
return {
isRunning
};
}),
save: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
name: import_zod.z.string(),
htmlUrl: import_zod.z.string(),
apiUrl: import_zod.z.string(),
customPort: import_zod.z.number(),
customUser: import_zod.z.string(),
isSystemWide: import_zod.z.boolean().default(false)
})
).mutation(async ({ input, ctx }) => {
const { teamId } = ctx.user;
let {
id,
name,
network,
engine,
isCoolifyProxyUsed,
remoteIpAddress,
remoteUser,
remotePort
} = input;
if (id === "new") {
if (engine) {
const { stdout } = await await (0, import_executeCommand.executeCommand)({
command: `docker network ls --filter 'name=^${network}$' --format '{{json .}}'`
});
if (stdout === "") {
await await (0, import_executeCommand.executeCommand)({
command: `docker network create --attachable ${network}`
});
}
await import_prisma.prisma.destinationDocker.create({
data: { name, teams: { connect: { id: teamId } }, engine, network, isCoolifyProxyUsed }
});
const destinations = await import_prisma.prisma.destinationDocker.findMany({ where: { engine } });
const destination = destinations.find((destination2) => destination2.network === network);
if (destinations.length > 0) {
const proxyConfigured = destinations.find(
(destination2) => destination2.network !== network && destination2.isCoolifyProxyUsed === true
);
if (proxyConfigured) {
isCoolifyProxyUsed = !!proxyConfigured.isCoolifyProxyUsed;
}
await import_prisma.prisma.destinationDocker.updateMany({
where: { engine },
data: { isCoolifyProxyUsed }
});
}
if (isCoolifyProxyUsed) {
await (0, import_common.startTraefikProxy)(destination.id);
}
return { id: destination.id };
} else {
const destination = await import_prisma.prisma.destinationDocker.create({
data: {
name,
teams: { connect: { id: teamId } },
engine,
network,
isCoolifyProxyUsed,
remoteEngine: true,
remoteIpAddress,
remoteUser,
remotePort: Number(remotePort)
}
});
return { id: destination.id };
}
} else {
await import_prisma.prisma.destinationDocker.update({ where: { id }, data: { name, engine, network } });
return {};
}
}),
check: import_trpc.privateProcedure.input(
import_zod.z.object({
network: import_zod.z.string()
})
).query(async ({ input, ctx }) => {
const { network } = input;
const found = await import_prisma.prisma.destinationDocker.findFirst({ where: { network } });
if (found) {
throw {
message: `Network already exists: ${network}`
};
}
}),
delete: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string()
})
).mutation(async ({ input, ctx }) => {
const { id } = input;
const { network, remoteVerified, engine, isCoolifyProxyUsed } = await import_prisma.prisma.destinationDocker.findUnique({ where: { id } });
if (isCoolifyProxyUsed) {
if (engine || remoteVerified) {
const { stdout: found } = await (0, import_executeCommand.executeCommand)({
dockerId: id,
command: `docker ps -a --filter network=${network} --filter name=coolify-proxy --format '{{.}}'`
});
if (found) {
await (0, import_executeCommand.executeCommand)({
dockerId: id,
command: `docker network disconnect ${network} coolify-proxy`
});
await (0, import_executeCommand.executeCommand)({ dockerId: id, command: `docker network rm ${network}` });
}
}
}
await import_prisma.prisma.destinationDocker.delete({ where: { id } });
}),
getDestinationById: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string()
})
).query(async ({ input, ctx }) => {
const { id } = input;
const { teamId } = ctx.user;
const destination = await import_prisma.prisma.destinationDocker.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { sshKey: true, application: true, service: true, database: true }
});
if (!destination && id !== "new") {
throw { status: 404, message: `Destination not found.` };
}
const settings = await (0, import_common.listSettings)();
return {
destination,
settings
};
})
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
destinationsRouter
});

View File

@@ -0,0 +1,25 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var routers_exports = {};
module.exports = __toCommonJS(routers_exports);
__reExport(routers_exports, require("./auth"), module.exports);
__reExport(routers_exports, require("./dashboard"), module.exports);
__reExport(routers_exports, require("./settings"), module.exports);
__reExport(routers_exports, require("./applications"), module.exports);
__reExport(routers_exports, require("./services"), module.exports);
__reExport(routers_exports, require("./databases"), module.exports);
__reExport(routers_exports, require("./sources"), module.exports);
__reExport(routers_exports, require("./destinations"), module.exports);

View File

@@ -0,0 +1,846 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var services_exports = {};
__export(services_exports, {
getServiceFromDB: () => getServiceFromDB,
servicesRouter: () => servicesRouter
});
module.exports = __toCommonJS(services_exports);
var import_zod = require("zod");
var import_js_yaml = __toESM(require("js-yaml"));
var import_promises = __toESM(require("fs/promises"));
var import_path = __toESM(require("path"));
var import_trpc = require("../../trpc");
var import_common = require("../../../lib/common");
var import_prisma = require("../../../prisma");
var import_executeCommand = require("../../../lib/executeCommand");
var import_lib = require("./lib");
var import_docker = require("../../../lib/docker");
var import_cuid = __toESM(require("cuid"));
var import_dayjs = require("../../../lib/dayjs");
const servicesRouter = (0, import_trpc.router)({
getLogs: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
containerId: import_zod.z.string(),
since: import_zod.z.number().optional().default(0)
})
).query(async ({ input, ctx }) => {
let { id, containerId, since } = input;
if (since !== 0) {
since = (0, import_dayjs.day)(since).unix();
}
const {
destinationDockerId,
destinationDocker: { id: dockerId }
} = await import_prisma.prisma.service.findUnique({
where: { id },
include: { destinationDocker: true }
});
if (destinationDockerId) {
try {
const { default: ansi } = await import("strip-ansi");
const { stdout, stderr } = await (0, import_executeCommand.executeCommand)({
dockerId,
command: `docker logs --since ${since} --tail 5000 --timestamps ${containerId}`
});
const stripLogsStdout = stdout.toString().split("\n").map((l) => ansi(l)).filter((a) => a);
const stripLogsStderr = stderr.toString().split("\n").map((l) => ansi(l)).filter((a) => a);
const logs = stripLogsStderr.concat(stripLogsStdout);
const sortedLogs = logs.sort(
(a, b) => (0, import_dayjs.day)(a.split(" ")[0]).isAfter((0, import_dayjs.day)(b.split(" ")[0])) ? 1 : -1
);
return {
data: {
logs: sortedLogs
}
};
} catch (error) {
const { statusCode, stderr } = error;
if (stderr.startsWith("Error: No such container")) {
return {
data: {
logs: [],
noContainer: true
}
};
}
if (statusCode === 404) {
return {
data: {
logs: []
}
};
}
}
}
return {
message: "No logs found."
};
}),
deleteStorage: import_trpc.privateProcedure.input(
import_zod.z.object({
storageId: import_zod.z.string()
})
).mutation(async ({ input, ctx }) => {
const { storageId } = input;
await import_prisma.prisma.servicePersistentStorage.deleteMany({ where: { id: storageId } });
}),
saveStorage: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
path: import_zod.z.string(),
isNewStorage: import_zod.z.boolean(),
storageId: import_zod.z.string().optional().nullable(),
containerId: import_zod.z.string().optional()
})
).mutation(async ({ input, ctx }) => {
const { id, path: path2, isNewStorage, storageId, containerId } = input;
if (isNewStorage) {
const volumeName = `${id}-custom${path2.replace(/\//gi, "-")}`;
const found = await import_prisma.prisma.servicePersistentStorage.findFirst({
where: { path: path2, containerId }
});
if (found) {
throw {
status: 500,
message: "Persistent storage already exists for this container and path."
};
}
await import_prisma.prisma.servicePersistentStorage.create({
data: { path: path2, volumeName, containerId, service: { connect: { id } } }
});
} else {
await import_prisma.prisma.servicePersistentStorage.update({
where: { id: storageId },
data: { path: path2, containerId }
});
}
}),
getStorages: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).query(async ({ input, ctx }) => {
const { id } = input;
const persistentStorages = await import_prisma.prisma.servicePersistentStorage.findMany({
where: { serviceId: id }
});
return {
success: true,
data: {
persistentStorages
}
};
}),
deleteSecret: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string(), name: import_zod.z.string() })).mutation(async ({ input, ctx }) => {
const { id, name } = input;
await import_prisma.prisma.serviceSecret.deleteMany({ where: { serviceId: id, name } });
}),
saveService: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
name: import_zod.z.string(),
fqdn: import_zod.z.string().optional(),
exposePort: import_zod.z.string().optional(),
type: import_zod.z.string(),
serviceSetting: import_zod.z.any(),
version: import_zod.z.string().optional()
})
).mutation(async ({ input, ctx }) => {
const teamId = ctx.user?.teamId;
let { id, name, fqdn, exposePort, type, serviceSetting, version } = input;
if (fqdn)
fqdn = fqdn.toLowerCase();
if (exposePort)
exposePort = Number(exposePort);
type = (0, import_common.fixType)(type);
const data = {
fqdn,
name,
exposePort,
version
};
const templates = await (0, import_common.getTemplates)();
const service = await import_prisma.prisma.service.findUnique({ where: { id } });
const foundTemplate = templates.find((t) => (0, import_common.fixType)(t.type) === (0, import_common.fixType)(service.type));
for (const setting of serviceSetting) {
let { id: settingId, name: name2, value, changed = false, isNew = false, variableName } = setting;
if (value) {
if (changed) {
await import_prisma.prisma.serviceSetting.update({ where: { id: settingId }, data: { value } });
}
if (isNew) {
if (!variableName) {
variableName = foundTemplate?.variables.find((v) => v.name === name2).id;
}
await import_prisma.prisma.serviceSetting.create({
data: { name: name2, value, variableName, service: { connect: { id } } }
});
}
}
}
await import_prisma.prisma.service.update({
where: { id },
data
});
}),
createSecret: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
name: import_zod.z.string(),
value: import_zod.z.string(),
isBuildSecret: import_zod.z.boolean().optional(),
isPRMRSecret: import_zod.z.boolean().optional(),
isNew: import_zod.z.boolean().optional()
})
).mutation(async ({ input }) => {
let { id, name, value, isNew } = input;
if (isNew) {
const found = await import_prisma.prisma.serviceSecret.findFirst({ where: { name, serviceId: id } });
if (found) {
throw `Secret ${name} already exists.`;
} else {
value = (0, import_common.encrypt)(value.trim());
await import_prisma.prisma.serviceSecret.create({
data: { name, value, service: { connect: { id } } }
});
}
} else {
value = (0, import_common.encrypt)(value.trim());
const found = await import_prisma.prisma.serviceSecret.findFirst({ where: { serviceId: id, name } });
if (found) {
await import_prisma.prisma.serviceSecret.updateMany({
where: { serviceId: id, name },
data: { value }
});
} else {
await import_prisma.prisma.serviceSecret.create({
data: { name, value, service: { connect: { id } } }
});
}
}
}),
getSecrets: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).query(async ({ input, ctx }) => {
const { id } = input;
const teamId = ctx.user?.teamId;
const service = await getServiceFromDB({ id, teamId });
let secrets = await import_prisma.prisma.serviceSecret.findMany({
where: { serviceId: id },
orderBy: { createdAt: "desc" }
});
const templates = await (0, import_common.getTemplates)();
if (!templates)
throw new Error("No templates found. Please contact support.");
const foundTemplate = templates.find((t) => (0, import_common.fixType)(t.type) === service.type);
secrets = secrets.map((secret) => {
const foundVariable = foundTemplate?.variables?.find((v) => v.name === secret.name) || null;
if (foundVariable) {
secret.readOnly = foundVariable.readOnly;
}
secret.value = (0, import_common.decrypt)(secret.value);
return secret;
});
return {
success: true,
data: {
secrets
}
};
}),
wordpress: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string(), ftpEnabled: import_zod.z.boolean() })).mutation(async ({ input, ctx }) => {
const { id } = input;
const teamId = ctx.user?.teamId;
const {
service: {
destinationDocker: { engine, remoteEngine, remoteIpAddress }
}
} = await import_prisma.prisma.wordpress.findUnique({
where: { serviceId: id },
include: { service: { include: { destinationDocker: true } } }
});
const publicPort = await (0, import_lib.getFreePublicPort)({ id, remoteEngine, engine, remoteIpAddress });
let ftpUser = (0, import_cuid.default)();
let ftpPassword = (0, import_lib.generatePassword)({});
const hostkeyDir = import_common.isDev ? "/tmp/hostkeys" : "/app/ssl/hostkeys";
try {
const data = await import_prisma.prisma.wordpress.update({
where: { serviceId: id },
data: { ftpEnabled },
include: { service: { include: { destinationDocker: true } } }
});
const {
service: { destinationDockerId, destinationDocker },
ftpPublicPort,
ftpUser: user,
ftpPassword: savedPassword,
ftpHostKey,
ftpHostKeyPrivate
} = data;
const { network, engine: engine2 } = destinationDocker;
if (ftpEnabled) {
if (user)
ftpUser = user;
if (savedPassword)
ftpPassword = (0, import_common.decrypt)(savedPassword);
const { stdout: password } = await (0, import_executeCommand.executeCommand)({
command: `echo ${ftpPassword} | openssl passwd -1 -stdin`,
shell: true
});
if (destinationDockerId) {
try {
await import_promises.default.stat(hostkeyDir);
} catch (error) {
await (0, import_executeCommand.executeCommand)({ command: `mkdir -p ${hostkeyDir}` });
}
if (!ftpHostKey) {
await (0, import_executeCommand.executeCommand)({
command: `ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -q -f ${hostkeyDir}/${id}.ed25519`
});
const { stdout: ftpHostKey2 } = await (0, import_executeCommand.executeCommand)({
command: `cat ${hostkeyDir}/${id}.ed25519`
});
await import_prisma.prisma.wordpress.update({
where: { serviceId: id },
data: { ftpHostKey: (0, import_common.encrypt)(ftpHostKey2) }
});
} else {
await (0, import_executeCommand.executeCommand)({
command: `echo "${(0, import_common.decrypt)(ftpHostKey)}" > ${hostkeyDir}/${id}.ed25519`,
shell: true
});
}
if (!ftpHostKeyPrivate) {
await (0, import_executeCommand.executeCommand)({
command: `ssh-keygen -t rsa -b 4096 -N "" -f ${hostkeyDir}/${id}.rsa`
});
const { stdout: ftpHostKeyPrivate2 } = await (0, import_executeCommand.executeCommand)({
command: `cat ${hostkeyDir}/${id}.rsa`
});
await import_prisma.prisma.wordpress.update({
where: { serviceId: id },
data: { ftpHostKeyPrivate: (0, import_common.encrypt)(ftpHostKeyPrivate2) }
});
} else {
await (0, import_executeCommand.executeCommand)({
command: `echo "${(0, import_common.decrypt)(ftpHostKeyPrivate)}" > ${hostkeyDir}/${id}.rsa`,
shell: true
});
}
await import_prisma.prisma.wordpress.update({
where: { serviceId: id },
data: {
ftpPublicPort: publicPort,
ftpUser: user ? void 0 : ftpUser,
ftpPassword: savedPassword ? void 0 : (0, import_common.encrypt)(ftpPassword)
}
});
try {
const { found: isRunning } = await (0, import_docker.checkContainer)({
dockerId: destinationDocker.id,
container: `${id}-ftp`
});
if (isRunning) {
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDocker.id,
command: `docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`,
shell: true
});
}
} catch (error) {
}
const volumes = [
`${id}-wordpress-data:/home/${ftpUser}/wordpress`,
`${import_common.isDev ? hostkeyDir : "/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys"}/${id}.ed25519:/etc/ssh/ssh_host_ed25519_key`,
`${import_common.isDev ? hostkeyDir : "/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys"}/${id}.rsa:/etc/ssh/ssh_host_rsa_key`,
`${import_common.isDev ? hostkeyDir : "/var/lib/docker/volumes/coolify-ssl-certs/_data/hostkeys"}/${id}.sh:/etc/sftp.d/chmod.sh`
];
const compose = {
version: "3.8",
services: {
[`${id}-ftp`]: {
image: `atmoz/sftp:alpine`,
command: `'${ftpUser}:${password.replace("\n", "").replace(/\$/g, "$$$")}:e:33'`,
extra_hosts: ["host.docker.internal:host-gateway"],
container_name: `${id}-ftp`,
volumes,
networks: [network],
depends_on: [],
restart: "always"
}
},
networks: {
[network]: {
external: true
}
},
volumes: {
[`${id}-wordpress-data`]: {
external: true,
name: `${id}-wordpress-data`
}
}
};
await import_promises.default.writeFile(
`${hostkeyDir}/${id}.sh`,
`#!/bin/bash
chmod 600 /etc/ssh/ssh_host_ed25519_key /etc/ssh/ssh_host_rsa_key
userdel -f xfs
chown -R 33:33 /home/${ftpUser}/wordpress/`
);
await (0, import_executeCommand.executeCommand)({ command: `chmod +x ${hostkeyDir}/${id}.sh` });
await import_promises.default.writeFile(`${hostkeyDir}/${id}-docker-compose.yml`, import_js_yaml.default.dump(compose));
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDocker.id,
command: `docker compose -f ${hostkeyDir}/${id}-docker-compose.yml up -d`
});
}
return {
publicPort,
ftpUser,
ftpPassword
};
} else {
await import_prisma.prisma.wordpress.update({
where: { serviceId: id },
data: { ftpPublicPort: null }
});
try {
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDocker.id,
command: `docker stop -t 0 ${id}-ftp && docker rm ${id}-ftp`,
shell: true
});
} catch (error) {
}
await (0, import_docker.stopTcpHttpProxy)(id, destinationDocker, ftpPublicPort);
}
} catch ({ status, message }) {
throw message;
} finally {
try {
await (0, import_executeCommand.executeCommand)({
command: `rm -fr ${hostkeyDir}/${id}-docker-compose.yml ${hostkeyDir}/${id}.ed25519 ${hostkeyDir}/${id}.ed25519.pub ${hostkeyDir}/${id}.rsa ${hostkeyDir}/${id}.rsa.pub ${hostkeyDir}/${id}.sh`
});
} catch (error) {
}
}
}),
start: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).mutation(async ({ input, ctx }) => {
const { id } = input;
const teamId = ctx.user?.teamId;
const service = await getServiceFromDB({ id, teamId });
const arm = (0, import_common.isARM)(service.arch);
const { type, destinationDockerId, destinationDocker, persistentStorage, exposePort } = service;
const { workdir } = await (0, import_common.createDirectories)({ repository: type, buildId: id });
const template = await (0, import_lib.parseAndFindServiceTemplates)(service, workdir, true);
const network = destinationDockerId && destinationDocker.network;
const config = {};
for (const s in template.services) {
let newEnvironments = [];
if (arm) {
if (template.services[s]?.environmentArm?.length > 0) {
for (const environment of template.services[s].environmentArm) {
let [env, ...value] = environment.split("=");
value = value.join("=");
if (!value.startsWith("$$secret") && value !== "") {
newEnvironments.push(`${env}=${value}`);
}
}
}
} else {
if (template.services[s]?.environment?.length > 0) {
for (const environment of template.services[s].environment) {
let [env, ...value] = environment.split("=");
value = value.join("=");
if (!value.startsWith("$$secret") && value !== "") {
newEnvironments.push(`${env}=${value}`);
}
}
}
}
const secrets = await (0, import_lib.verifyAndDecryptServiceSecrets)(id);
for (const secret of secrets) {
const { name, value } = secret;
if (value) {
const foundEnv = !!template.services[s].environment?.find(
(env) => env.startsWith(`${name}=`)
);
const foundNewEnv = !!newEnvironments?.find((env) => env.startsWith(`${name}=`));
if (foundEnv && !foundNewEnv) {
newEnvironments.push(`${name}=${value}`);
}
if (!foundEnv && !foundNewEnv && s === id) {
newEnvironments.push(`${name}=${value}`);
}
}
}
const customVolumes = await import_prisma.prisma.servicePersistentStorage.findMany({
where: { serviceId: id }
});
let volumes = /* @__PURE__ */ new Set();
if (arm) {
template.services[s]?.volumesArm && template.services[s].volumesArm.length > 0 && template.services[s].volumesArm.forEach((v) => volumes.add(v));
} else {
template.services[s]?.volumes && template.services[s].volumes.length > 0 && template.services[s].volumes.forEach((v) => volumes.add(v));
}
if (service.type === "plausibleanalytics" && service.plausibleAnalytics?.id) {
let temp = Array.from(volumes);
temp.forEach((a) => {
const t = a.replace(service.id, service.plausibleAnalytics.id);
volumes.delete(a);
volumes.add(t);
});
}
if (customVolumes.length > 0) {
for (const customVolume of customVolumes) {
const { volumeName, path: path2, containerId } = customVolume;
if (volumes && volumes.size > 0 && !volumes.has(`${volumeName}:${path2}`) && containerId === service) {
volumes.add(`${volumeName}:${path2}`);
}
}
}
let ports = [];
if (template.services[s].proxy?.length > 0) {
for (const proxy of template.services[s].proxy) {
if (proxy.hostPort) {
ports.push(`${proxy.hostPort}:${proxy.port}`);
}
}
} else {
if (template.services[s].ports?.length === 1) {
for (const port of template.services[s].ports) {
if (exposePort) {
ports.push(`${exposePort}:${port}`);
}
}
}
}
let image = template.services[s].image;
if (arm && template.services[s].imageArm) {
image = template.services[s].imageArm;
}
config[s] = {
container_name: s,
build: template.services[s].build || void 0,
command: template.services[s].command,
entrypoint: template.services[s]?.entrypoint,
image,
expose: template.services[s].ports,
ports: ports.length > 0 ? ports : void 0,
volumes: Array.from(volumes),
environment: newEnvironments,
depends_on: template.services[s]?.depends_on,
ulimits: template.services[s]?.ulimits,
cap_drop: template.services[s]?.cap_drop,
cap_add: template.services[s]?.cap_add,
labels: (0, import_common.makeLabelForServices)(type),
...(0, import_docker.defaultComposeConfiguration)(network)
};
if (template.services[s]?.files?.length > 0) {
if (!config[s].build) {
config[s].build = {
context: workdir,
dockerfile: `Dockerfile.${s}`
};
}
let Dockerfile = `
FROM ${template.services[s].image}`;
for (const file of template.services[s].files) {
const { location, content } = file;
const source = import_path.default.join(workdir, location);
await import_promises.default.mkdir(import_path.default.dirname(source), { recursive: true });
await import_promises.default.writeFile(source, content);
Dockerfile += `
COPY .${location} ${location}`;
}
await import_promises.default.writeFile(`${workdir}/Dockerfile.${s}`, Dockerfile);
}
}
const { volumeMounts } = (0, import_lib.persistentVolumes)(id, persistentStorage, config);
const composeFile = {
version: "3.8",
services: config,
networks: {
[network]: {
external: true
}
},
volumes: volumeMounts
};
const composeFileDestination = `${workdir}/docker-compose.yaml`;
await import_promises.default.writeFile(composeFileDestination, import_js_yaml.default.dump(composeFile));
let fastify = null;
await (0, import_lib.startServiceContainers)(fastify, id, teamId, destinationDocker.id, composeFileDestination);
if (service.type === "minio") {
try {
const { stdout: containers } = await (0, import_executeCommand.executeCommand)({
dockerId: destinationDocker.id,
command: `docker container ls -a --filter 'name=${id}-' --format {{.ID}}`
});
if (containers) {
const containerArray = containers.split("\n");
if (containerArray.length > 0) {
for (const container of containerArray) {
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDockerId,
command: `docker stop -t 0 ${container}`
});
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDockerId,
command: `docker rm --force ${container}`
});
}
}
}
} catch (error) {
}
try {
const { stdout: containers } = await (0, import_executeCommand.executeCommand)({
dockerId: destinationDocker.id,
command: `docker container ls -a --filter 'name=${id}-' --format {{.ID}}`
});
if (containers) {
const containerArray = containers.split("\n");
if (containerArray.length > 0) {
for (const container of containerArray) {
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDockerId,
command: `docker stop -t 0 ${container}`
});
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDockerId,
command: `docker rm --force ${container}`
});
}
}
}
} catch (error) {
}
}
}),
stop: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).mutation(async ({ input, ctx }) => {
const { id } = input;
const teamId = ctx.user?.teamId;
const { destinationDockerId } = await getServiceFromDB({ id, teamId });
if (destinationDockerId) {
const { stdout: containers } = await (0, import_executeCommand.executeCommand)({
dockerId: destinationDockerId,
command: `docker ps -a --filter 'label=com.docker.compose.project=${id}' --format {{.ID}}`
});
if (containers) {
const containerArray = containers.split("\n");
if (containerArray.length > 0) {
for (const container of containerArray) {
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDockerId,
command: `docker stop -t 0 ${container}`
});
await (0, import_executeCommand.executeCommand)({
dockerId: destinationDockerId,
command: `docker rm --force ${container}`
});
}
}
}
return {};
}
}),
getServices: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).query(async ({ input, ctx }) => {
const { id } = input;
const teamId = ctx.user?.teamId;
const service = await getServiceFromDB({ id, teamId });
if (!service) {
throw { status: 404, message: "Service not found." };
}
let template = {};
let tags = [];
if (service.type) {
template = await (0, import_lib.parseAndFindServiceTemplates)(service);
tags = await (0, import_common.getTags)(service.type);
}
return {
success: true,
data: {
settings: await (0, import_common.listSettings)(),
service,
template,
tags
}
};
}),
status: import_trpc.privateProcedure.input(import_zod.z.object({ id: import_zod.z.string() })).query(async ({ ctx, input }) => {
const id = input.id;
const teamId = ctx.user?.teamId;
if (!teamId) {
throw { status: 400, message: "Team not found." };
}
const service = await getServiceFromDB({ id, teamId });
const { destinationDockerId } = service;
let payload = {};
if (destinationDockerId) {
const { stdout: containers } = await (0, import_executeCommand.executeCommand)({
dockerId: service.destinationDocker.id,
command: `docker ps -a --filter "label=com.docker.compose.project=${id}" --format '{{json .}}'`
});
if (containers) {
const containersArray = containers.trim().split("\n");
if (containersArray.length > 0 && containersArray[0] !== "") {
const templates = await (0, import_common.getTemplates)();
let template = templates.find((t) => t.type === service.type);
const templateStr = JSON.stringify(template);
if (templateStr) {
template = JSON.parse(templateStr.replaceAll("$$id", service.id));
}
for (const container of containersArray) {
let isRunning = false;
let isExited = false;
let isRestarting = false;
let isExcluded = false;
const containerObj = JSON.parse(container);
const exclude = template?.services[containerObj.Names]?.exclude;
if (exclude) {
payload[containerObj.Names] = {
status: {
isExcluded: true,
isRunning: false,
isExited: false,
isRestarting: false
}
};
continue;
}
const status = containerObj.State;
if (status === "running") {
isRunning = true;
}
if (status === "exited") {
isExited = true;
}
if (status === "restarting") {
isRestarting = true;
}
payload[containerObj.Names] = {
status: {
isExcluded,
isRunning,
isExited,
isRestarting
}
};
}
}
}
}
return payload;
}),
cleanup: import_trpc.privateProcedure.query(async ({ ctx }) => {
const teamId = ctx.user?.teamId;
let services = await import_prisma.prisma.service.findMany({
where: { teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: { destinationDocker: true, teams: true }
});
for (const service of services) {
if (!service.fqdn) {
if (service.destinationDockerId) {
const { stdout: containers } = await (0, import_executeCommand.executeCommand)({
dockerId: service.destinationDockerId,
command: `docker ps -a --filter 'label=com.docker.compose.project=${service.id}' --format {{.ID}}`
});
if (containers) {
const containerArray = containers.split("\n");
if (containerArray.length > 0) {
for (const container of containerArray) {
await (0, import_executeCommand.executeCommand)({
dockerId: service.destinationDockerId,
command: `docker stop -t 0 ${container}`
});
await (0, import_executeCommand.executeCommand)({
dockerId: service.destinationDockerId,
command: `docker rm --force ${container}`
});
}
}
}
}
await (0, import_common.removeService)({ id: service.id });
}
}
}),
delete: import_trpc.privateProcedure.input(import_zod.z.object({ force: import_zod.z.boolean(), id: import_zod.z.string() })).mutation(async ({ input }) => {
const { id } = input;
await import_prisma.prisma.serviceSecret.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.serviceSetting.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.servicePersistentStorage.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.meiliSearch.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.fider.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.ghost.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.umami.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.hasura.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.plausibleAnalytics.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.minio.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.vscodeserver.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.wordpress.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.glitchTip.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.moodle.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.appwrite.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.searxng.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.weblate.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.taiga.deleteMany({ where: { serviceId: id } });
await import_prisma.prisma.service.delete({ where: { id } });
return {};
})
});
async function getServiceFromDB({
id,
teamId
}) {
const settings = await import_prisma.prisma.setting.findFirst();
const body = await import_prisma.prisma.service.findFirst({
where: { id, teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
include: {
destinationDocker: true,
persistentStorage: true,
serviceSecret: true,
serviceSetting: true,
wordpress: true,
plausibleAnalytics: true
}
});
if (!body) {
return null;
}
if (body?.serviceSecret.length > 0) {
body.serviceSecret = body.serviceSecret.map((s) => {
s.value = (0, import_common.decrypt)(s.value);
return s;
});
}
if (body.wordpress) {
body.wordpress.ftpPassword = (0, import_common.decrypt)(body.wordpress.ftpPassword);
}
return { ...body, settings };
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getServiceFromDB,
servicesRouter
});

View File

@@ -0,0 +1,371 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var lib_exports = {};
__export(lib_exports, {
generatePassword: () => generatePassword,
getFreePublicPort: () => getFreePublicPort,
parseAndFindServiceTemplates: () => parseAndFindServiceTemplates,
persistentVolumes: () => persistentVolumes,
startServiceContainers: () => startServiceContainers,
verifyAndDecryptServiceSecrets: () => verifyAndDecryptServiceSecrets
});
module.exports = __toCommonJS(lib_exports);
var import_common = require("../../../lib/common");
var import_bcryptjs = __toESM(require("bcryptjs"));
var import_prisma = require("../../../prisma");
var import_crypto = __toESM(require("crypto"));
var import_executeCommand = require("../../../lib/executeCommand");
async function parseAndFindServiceTemplates(service, workdir, isDeploy = false) {
const templates = await (0, import_common.getTemplates)();
const foundTemplate = templates.find((t) => (0, import_common.fixType)(t.type) === service.type);
let parsedTemplate = {};
if (foundTemplate) {
if (!isDeploy) {
for (const [key, value] of Object.entries(foundTemplate.services)) {
const realKey = key.replace("$$id", service.id);
let name = value.name;
if (!name) {
if (Object.keys(foundTemplate.services).length === 1) {
name = foundTemplate.name || service.name.toLowerCase();
} else {
if (key === "$$id") {
name = foundTemplate.name || key.replaceAll("$$id-", "") || service.name.toLowerCase();
} else {
name = key.replaceAll("$$id-", "") || service.name.toLowerCase();
}
}
}
parsedTemplate[realKey] = {
value,
name,
documentation: value.documentation || foundTemplate.documentation || "https://docs.coollabs.io",
image: value.image,
files: value?.files,
environment: [],
fqdns: [],
hostPorts: [],
proxy: {}
};
if (value.environment?.length > 0) {
for (const env of value.environment) {
let [envKey, ...envValue] = env.split("=");
envValue = envValue.join("=");
let variable = null;
if (foundTemplate?.variables) {
variable = foundTemplate?.variables.find((v) => v.name === envKey) || foundTemplate?.variables.find((v) => v.id === envValue);
}
if (variable) {
const id = variable.id.replaceAll("$$", "");
const label = variable?.label;
const description = variable?.description;
const defaultValue = variable?.defaultValue;
const main = variable?.main || "$$id";
const type = variable?.type || "input";
const placeholder = variable?.placeholder || "";
const readOnly = variable?.readOnly || false;
const required = variable?.required || false;
if (envValue.startsWith("$$config") || variable?.showOnConfiguration) {
if (envValue.startsWith("$$config_coolify")) {
continue;
}
parsedTemplate[realKey].environment.push({
id,
name: envKey,
value: envValue,
main,
label,
description,
defaultValue,
type,
placeholder,
required,
readOnly
});
}
}
}
}
if (value?.proxy && value.proxy.length > 0) {
for (const proxyValue of value.proxy) {
if (proxyValue.domain) {
const variable = foundTemplate?.variables.find((v) => v.id === proxyValue.domain);
if (variable) {
const { id, name: name2, label, description, defaultValue, required = false } = variable;
const found = await import_prisma.prisma.serviceSetting.findFirst({
where: { serviceId: service.id, variableName: proxyValue.domain }
});
parsedTemplate[realKey].fqdns.push({
id,
name: name2,
value: found?.value || "",
label,
description,
defaultValue,
required
});
}
}
if (proxyValue.hostPort) {
const variable = foundTemplate?.variables.find((v) => v.id === proxyValue.hostPort);
if (variable) {
const { id, name: name2, label, description, defaultValue, required = false } = variable;
const found = await import_prisma.prisma.serviceSetting.findFirst({
where: { serviceId: service.id, variableName: proxyValue.hostPort }
});
parsedTemplate[realKey].hostPorts.push({
id,
name: name2,
value: found?.value || "",
label,
description,
defaultValue,
required
});
}
}
}
}
}
} else {
parsedTemplate = foundTemplate;
}
let strParsedTemplate = JSON.stringify(parsedTemplate);
strParsedTemplate = strParsedTemplate.replaceAll("$$id", service.id);
strParsedTemplate = strParsedTemplate.replaceAll(
"$$core_version",
service.version || foundTemplate.defaultVersion
);
if (workdir) {
strParsedTemplate = strParsedTemplate.replaceAll("$$workdir", workdir);
}
if (service.serviceSetting.length > 0) {
for (const setting of service.serviceSetting) {
const { value, variableName } = setting;
const regex = new RegExp(`\\$\\$config_${variableName.replace("$$config_", "")}"`, "gi");
if (value === "$$generate_fqdn") {
strParsedTemplate = strParsedTemplate.replaceAll(regex, service.fqdn + '"' || '"');
} else if (value === "$$generate_fqdn_slash") {
strParsedTemplate = strParsedTemplate.replaceAll(regex, service.fqdn + '/"');
} else if (value === "$$generate_domain") {
strParsedTemplate = strParsedTemplate.replaceAll(regex, (0, import_common.getDomain)(service.fqdn) + '"');
} else if (service.destinationDocker?.network && value === "$$generate_network") {
strParsedTemplate = strParsedTemplate.replaceAll(
regex,
service.destinationDocker.network + '"'
);
} else {
strParsedTemplate = strParsedTemplate.replaceAll(regex, value + '"');
}
}
}
if (service.serviceSecret.length > 0) {
for (const secret of service.serviceSecret) {
let { name, value } = secret;
name = name.toLowerCase();
const regexHashed = new RegExp(`\\$\\$hashed\\$\\$secret_${name}`, "gi");
const regex = new RegExp(`\\$\\$secret_${name}`, "gi");
if (value) {
strParsedTemplate = strParsedTemplate.replaceAll(
regexHashed,
import_bcryptjs.default.hashSync(value.replaceAll('"', '\\"'), 10)
);
strParsedTemplate = strParsedTemplate.replaceAll(regex, value.replaceAll('"', '\\"'));
} else {
strParsedTemplate = strParsedTemplate.replaceAll(regexHashed, "");
strParsedTemplate = strParsedTemplate.replaceAll(regex, "");
}
}
}
parsedTemplate = JSON.parse(strParsedTemplate);
}
return parsedTemplate;
}
function generatePassword({
length = 24,
symbols = false,
isHex = false
}) {
if (isHex) {
return import_crypto.default.randomBytes(length).toString("hex");
}
const password = generator.generate({
length,
numbers: true,
strict: true,
symbols
});
return password;
}
async function getFreePublicPort({ id, remoteEngine, engine, remoteIpAddress }) {
const { default: isReachable } = await import("is-port-reachable");
const data = await import_prisma.prisma.setting.findFirst();
const { minPort, maxPort } = data;
if (remoteEngine) {
const dbUsed = await (await import_prisma.prisma.database.findMany({
where: {
publicPort: { not: null },
id: { not: id },
destinationDocker: { remoteIpAddress }
},
select: { publicPort: true }
})).map((a) => a.publicPort);
const wpFtpUsed = await (await import_prisma.prisma.wordpress.findMany({
where: {
ftpPublicPort: { not: null },
id: { not: id },
service: { destinationDocker: { remoteIpAddress } }
},
select: { ftpPublicPort: true }
})).map((a) => a.ftpPublicPort);
const wpUsed = await (await import_prisma.prisma.wordpress.findMany({
where: {
mysqlPublicPort: { not: null },
id: { not: id },
service: { destinationDocker: { remoteIpAddress } }
},
select: { mysqlPublicPort: true }
})).map((a) => a.mysqlPublicPort);
const minioUsed = await (await import_prisma.prisma.minio.findMany({
where: {
publicPort: { not: null },
id: { not: id },
service: { destinationDocker: { remoteIpAddress } }
},
select: { publicPort: true }
})).map((a) => a.publicPort);
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
const range = (0, import_common.generateRangeArray)(minPort, maxPort);
const availablePorts = range.filter((port) => !usedPorts.includes(port));
for (const port of availablePorts) {
const found = await isReachable(port, { host: remoteIpAddress });
if (!found) {
return port;
}
}
return false;
} else {
const dbUsed = await (await import_prisma.prisma.database.findMany({
where: { publicPort: { not: null }, id: { not: id }, destinationDocker: { engine } },
select: { publicPort: true }
})).map((a) => a.publicPort);
const wpFtpUsed = await (await import_prisma.prisma.wordpress.findMany({
where: {
ftpPublicPort: { not: null },
id: { not: id },
service: { destinationDocker: { engine } }
},
select: { ftpPublicPort: true }
})).map((a) => a.ftpPublicPort);
const wpUsed = await (await import_prisma.prisma.wordpress.findMany({
where: {
mysqlPublicPort: { not: null },
id: { not: id },
service: { destinationDocker: { engine } }
},
select: { mysqlPublicPort: true }
})).map((a) => a.mysqlPublicPort);
const minioUsed = await (await import_prisma.prisma.minio.findMany({
where: {
publicPort: { not: null },
id: { not: id },
service: { destinationDocker: { engine } }
},
select: { publicPort: true }
})).map((a) => a.publicPort);
const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed];
const range = (0, import_common.generateRangeArray)(minPort, maxPort);
const availablePorts = range.filter((port) => !usedPorts.includes(port));
for (const port of availablePorts) {
const found = await isReachable(port, { host: "localhost" });
if (!found) {
return port;
}
}
return false;
}
}
async function verifyAndDecryptServiceSecrets(id) {
const secrets = await import_prisma.prisma.serviceSecret.findMany({ where: { serviceId: id } });
let decryptedSecrets = secrets.map((secret) => {
const { name, value } = secret;
if (value) {
let rawValue = (0, import_common.decrypt)(value);
rawValue = rawValue.replaceAll(/\$/gi, "$$$");
return { name, value: rawValue };
}
return { name, value };
});
return decryptedSecrets;
}
function persistentVolumes(id, persistentStorage, config) {
let volumeSet = /* @__PURE__ */ new Set();
if (Object.keys(config).length > 0) {
for (const [key, value] of Object.entries(config)) {
if (value.volumes) {
for (const volume of value.volumes) {
if (!volume.startsWith("/")) {
volumeSet.add(volume);
}
}
}
}
}
const volumesArray = Array.from(volumeSet);
const persistentVolume = persistentStorage?.map((storage) => {
return `${id}${storage.path.replace(/\//gi, "-")}:${storage.path}`;
}) || [];
let volumes = [...persistentVolume];
if (volumesArray)
volumes = [...volumesArray, ...volumes];
const composeVolumes = volumes.length > 0 && volumes.map((volume) => {
return {
[`${volume.split(":")[0]}`]: {
name: volume.split(":")[0]
}
};
}) || [];
const volumeMounts = Object.assign({}, ...composeVolumes) || {};
return { volumeMounts };
}
async function startServiceContainers(fastify, id, teamId, dockerId, composeFileDestination) {
try {
await (0, import_executeCommand.executeCommand)({ dockerId, command: `docker compose -f ${composeFileDestination} pull` });
} catch (error) {
}
await (0, import_executeCommand.executeCommand)({ dockerId, command: `docker compose -f ${composeFileDestination} build --no-cache` });
await (0, import_executeCommand.executeCommand)({ dockerId, command: `docker compose -f ${composeFileDestination} create` });
await (0, import_executeCommand.executeCommand)({ dockerId, command: `docker compose -f ${composeFileDestination} start` });
await (0, import_common.asyncSleep)(1e3);
await (0, import_executeCommand.executeCommand)({ dockerId, command: `docker compose -f ${composeFileDestination} up -d` });
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
generatePassword,
getFreePublicPort,
parseAndFindServiceTemplates,
persistentVolumes,
startServiceContainers,
verifyAndDecryptServiceSecrets
});

View File

@@ -0,0 +1,108 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var settings_exports = {};
__export(settings_exports, {
settingsRouter: () => settingsRouter
});
module.exports = __toCommonJS(settings_exports);
var import_trpc = require("../trpc");
var import_server = require("@trpc/server");
var import_common = require("../../lib/common");
var import_env = require("../../env");
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
const settingsRouter = (0, import_trpc.router)({
getBaseSettings: import_trpc.publicProcedure.query(async () => {
const settings = await (0, import_common.listSettings)();
return {
success: true,
data: {
isRegistrationEnabled: settings?.isRegistrationEnabled
}
};
}),
getInstanceSettings: import_trpc.privateProcedure.query(async ({ ctx }) => {
try {
const settings = await (0, import_common.listSettings)();
let isAdmin = false;
let permission = null;
let token = null;
let pendingInvitations = [];
if (!settings) {
throw new import_server.TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "An unexpected error occurred, please try again later."
});
}
if (ctx.user) {
const currentUser = await (0, import_common.getCurrentUser)(ctx.user.userId);
if (currentUser) {
const foundPermission = currentUser.permission.find(
(p) => p.teamId === ctx.user?.teamId
)?.permission;
if (foundPermission) {
permission = foundPermission;
isAdmin = foundPermission === "owner" || foundPermission === "admin";
}
const payload = {
userId: ctx.user?.userId,
teamId: ctx.user?.teamId,
permission,
isAdmin,
iat: Math.floor(Date.now() / 1e3)
};
token = import_jsonwebtoken.default.sign(payload, import_env.env.COOLIFY_SECRET_KEY);
}
pendingInvitations = await (0, import_common.getTeamInvitation)(ctx.user.userId);
}
return {
success: true,
data: {
token,
userId: ctx.user?.userId,
teamId: ctx.user?.teamId,
permission,
isAdmin,
ipv4: ctx.user?.teamId ? settings.ipv4 : null,
ipv6: ctx.user?.teamId ? settings.ipv6 : null,
version: import_common.version,
whiteLabeled: import_env.env.COOLIFY_WHITE_LABELED === "true",
whiteLabeledIcon: import_env.env.COOLIFY_WHITE_LABELED_ICON,
isRegistrationEnabled: settings.isRegistrationEnabled,
pendingInvitations
}
};
} catch (error) {
throw new import_server.TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "An unexpected error occurred, please try again later.",
cause: error
});
}
})
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
settingsRouter
});

View File

@@ -0,0 +1,241 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var sources_exports = {};
__export(sources_exports, {
sourcesRouter: () => sourcesRouter
});
module.exports = __toCommonJS(sources_exports);
var import_zod = require("zod");
var import_trpc = require("../../trpc");
var import_common = require("../../../lib/common");
var import_prisma = require("../../../prisma");
var import_cuid = __toESM(require("cuid"));
const sourcesRouter = (0, import_trpc.router)({
save: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
name: import_zod.z.string(),
htmlUrl: import_zod.z.string(),
apiUrl: import_zod.z.string(),
customPort: import_zod.z.number(),
customUser: import_zod.z.string(),
isSystemWide: import_zod.z.boolean().default(false)
})
).mutation(async ({ input, ctx }) => {
let { id, name, htmlUrl, apiUrl, customPort, customUser, isSystemWide } = input;
if (customPort)
customPort = Number(customPort);
await import_prisma.prisma.gitSource.update({
where: { id },
data: { name, htmlUrl, apiUrl, customPort, customUser, isSystemWide }
});
}),
newGitHubApp: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
name: import_zod.z.string(),
htmlUrl: import_zod.z.string(),
apiUrl: import_zod.z.string(),
organization: import_zod.z.string(),
customPort: import_zod.z.number(),
isSystemWide: import_zod.z.boolean().default(false)
})
).mutation(async ({ ctx, input }) => {
const { teamId } = ctx.user;
let { id, name, htmlUrl, apiUrl, organization, customPort, isSystemWide } = input;
if (customPort)
customPort = Number(customPort);
if (id === "new") {
const newId = (0, import_cuid.default)();
await import_prisma.prisma.gitSource.create({
data: {
id: newId,
name,
htmlUrl,
apiUrl,
organization,
customPort,
isSystemWide,
type: "github",
teams: { connect: { id: teamId } }
}
});
return {
id: newId
};
}
return null;
}),
newGitLabApp: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string(),
type: import_zod.z.string(),
name: import_zod.z.string(),
htmlUrl: import_zod.z.string(),
apiUrl: import_zod.z.string(),
oauthId: import_zod.z.number(),
appId: import_zod.z.string(),
appSecret: import_zod.z.string(),
groupName: import_zod.z.string().optional().nullable(),
customPort: import_zod.z.number().optional().nullable(),
customUser: import_zod.z.string().optional().nullable()
})
).mutation(async ({ input, ctx }) => {
const { teamId } = ctx.user;
let {
id,
type,
name,
htmlUrl,
apiUrl,
oauthId,
appId,
appSecret,
groupName,
customPort,
customUser
} = input;
if (oauthId)
oauthId = Number(oauthId);
if (customPort)
customPort = Number(customPort);
const encryptedAppSecret = (0, import_common.encrypt)(appSecret);
if (id === "new") {
const newId = (0, import_cuid.default)();
await import_prisma.prisma.gitSource.create({
data: {
id: newId,
type,
apiUrl,
htmlUrl,
name,
customPort,
customUser,
teams: { connect: { id: teamId } }
}
});
await import_prisma.prisma.gitlabApp.create({
data: {
teams: { connect: { id: teamId } },
appId,
oauthId,
groupName,
appSecret: encryptedAppSecret,
gitSource: { connect: { id: newId } }
}
});
return {
status: 201,
id: newId
};
} else {
await import_prisma.prisma.gitSource.update({
where: { id },
data: { type, apiUrl, htmlUrl, name, customPort, customUser }
});
await import_prisma.prisma.gitlabApp.update({
where: { id },
data: {
appId,
oauthId,
groupName,
appSecret: encryptedAppSecret
}
});
}
}),
delete: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string()
})
).mutation(async ({ input, ctx }) => {
const { id } = input;
const source = await import_prisma.prisma.gitSource.delete({
where: { id },
include: { githubApp: true, gitlabApp: true }
});
if (source.githubAppId) {
await import_prisma.prisma.githubApp.delete({ where: { id: source.githubAppId } });
}
if (source.gitlabAppId) {
await import_prisma.prisma.gitlabApp.delete({ where: { id: source.gitlabAppId } });
}
}),
getSourceById: import_trpc.privateProcedure.input(
import_zod.z.object({
id: import_zod.z.string()
})
).query(async ({ input, ctx }) => {
const { id } = input;
const { teamId } = ctx.user;
const settings = await import_prisma.prisma.setting.findFirst({});
if (id === "new") {
return {
source: {
name: null,
type: null,
htmlUrl: null,
apiUrl: null,
organization: null,
customPort: 22,
customUser: "git"
},
settings
};
}
const source = await import_prisma.prisma.gitSource.findFirst({
where: {
id,
OR: [
{ teams: { some: { id: teamId === "0" ? void 0 : teamId } } },
{ isSystemWide: true }
]
},
include: { githubApp: true, gitlabApp: true }
});
if (!source) {
throw { status: 404, message: "Source not found." };
}
if (source?.githubApp?.clientSecret)
source.githubApp.clientSecret = (0, import_common.decrypt)(source.githubApp.clientSecret);
if (source?.githubApp?.webhookSecret)
source.githubApp.webhookSecret = (0, import_common.decrypt)(source.githubApp.webhookSecret);
if (source?.githubApp?.privateKey)
source.githubApp.privateKey = (0, import_common.decrypt)(source.githubApp.privateKey);
if (source?.gitlabApp?.appSecret)
source.gitlabApp.appSecret = (0, import_common.decrypt)(source.gitlabApp.appSecret);
return {
success: true,
data: {
source,
settings
}
};
})
});
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
sourcesRouter
});

View File

@@ -0,0 +1,65 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var trpc_exports = {};
__export(trpc_exports, {
privateProcedure: () => privateProcedure,
publicProcedure: () => publicProcedure,
router: () => router
});
module.exports = __toCommonJS(trpc_exports);
var import_server = require("@trpc/server");
var import_superjson = __toESM(require("superjson"));
const t = import_server.initTRPC.context().create({
transformer: import_superjson.default,
errorFormatter({ shape }) {
return shape;
}
});
const logger = t.middleware(async ({ path, type, next }) => {
const start = Date.now();
const result = await next();
const durationMs = Date.now() - start;
result.ok ? console.log("OK request timing:", { path, type, durationMs }) : console.log("Non-OK request timing", { path, type, durationMs });
return result;
});
const isAdmin = t.middleware(async ({ ctx, next }) => {
if (!ctx.user) {
throw new import_server.TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
user: ctx.user
}
});
});
const router = t.router;
const privateProcedure = t.procedure.use(isAdmin);
const publicProcedure = t.procedure;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
privateProcedure,
publicProcedure,
router
});