@@ -149,7 +155,7 @@ export default function Home() {
Home.getLayout = (page: ReactElement) => {
return
{page} ;
};
-export async function getServerSideProps(_context: GetServerSidePropsContext) {
+export async function getServerSideProps(context: GetServerSidePropsContext) {
if (!IS_CLOUD) {
return {
redirect: {
diff --git a/apps/dokploy/pages/swagger.tsx b/apps/dokploy/pages/swagger.tsx
index 11ea0731..b5deb2ac 100644
--- a/apps/dokploy/pages/swagger.tsx
+++ b/apps/dokploy/pages/swagger.tsx
@@ -30,41 +30,7 @@ const Home: NextPage = () => {
return (
- (args: any) => {
- const result = ori(args);
- const apiKey = args?.apiKey?.value;
- if (apiKey) {
- localStorage.setItem("swagger_api_key", apiKey);
- }
- return result;
- },
- logout: (ori: any) => (args: any) => {
- const result = ori(args);
- localStorage.removeItem("swagger_api_key");
- return result;
- },
- },
- },
- },
- },
- ]}
- requestInterceptor={(request: any) => {
- const apiKey = localStorage.getItem("swagger_api_key");
- if (apiKey) {
- request.headers = request.headers || {};
- request.headers["x-api-key"] = apiKey;
- }
- return request;
- }}
- />
+
);
};
@@ -72,7 +38,7 @@ const Home: NextPage = () => {
export default Home;
export async function getServerSideProps(context: GetServerSidePropsContext) {
const { req, res } = context;
- const { user, session } = await validateRequest(context.req);
+ const { user, session } = await validateRequest(context.req, context.res);
if (!user) {
return {
redirect: {
@@ -87,17 +53,17 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
req: req as any,
res: res as any,
db: null as any,
- session: session as any,
- user: user as any,
+ session: session,
+ user: user,
},
transformer: superjson,
});
- if (user.role === "member") {
- const userR = await helpers.user.one.fetch({
- userId: user.id,
+ if (user.rol === "user") {
+ const result = await helpers.user.byAuthId.fetch({
+ authId: user.id,
});
- if (!userR?.canAccessToAPI) {
+ if (!result.canAccessToAPI) {
return {
redirect: {
permanent: true,
diff --git a/apps/dokploy/public/locales/ml/common.json b/apps/dokploy/public/locales/ml/common.json
deleted file mode 100644
index 0967ef42..00000000
--- a/apps/dokploy/public/locales/ml/common.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/apps/dokploy/public/locales/ml/settings.json b/apps/dokploy/public/locales/ml/settings.json
deleted file mode 100644
index cb62b6ec..00000000
--- a/apps/dokploy/public/locales/ml/settings.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "settings.common.save": "സേവ് ചെയ്യുക",
- "settings.common.enterTerminal": "ടർമിനലിൽ പ്രവേശിക്കുക",
- "settings.server.domain.title": "സർവർ ഡോമെയ്ൻ",
- "settings.server.domain.description": "നിങ്ങളുടെ സർവർ അപ്ലിക്കേഷനിൽ ഒരു ഡോമെയ്ൻ ചേർക്കുക.",
- "settings.server.domain.form.domain": "ഡോമെയ്ൻ",
- "settings.server.domain.form.letsEncryptEmail": "ലെറ്റ്സ് എൻക്രിപ്റ്റ് ഇമെയിൽ",
- "settings.server.domain.form.certificate.label": "സർട്ടിഫിക്കറ്റ് പ്രൊവൈഡർ",
- "settings.server.domain.form.certificate.placeholder": "ഒരു സർട്ടിഫിക്കറ്റ് തിരഞ്ഞെടുക്കുക",
- "settings.server.domain.form.certificateOptions.none": "ഒന്നുമില്ല",
- "settings.server.domain.form.certificateOptions.letsencrypt": "ലെറ്റ്സ് എൻക്രിപ്റ്റ്",
-
- "settings.server.webServer.title": "വെബ് സർവർ",
- "settings.server.webServer.description": "വെബ് സർവർ റീലോഡ് ചെയ്യുക അല്ലെങ്കിൽ ശുചീകരിക്കുക.",
- "settings.server.webServer.actions": "നടപടികൾ",
- "settings.server.webServer.reload": "റീലോഡ് ചെയ്യുക",
- "settings.server.webServer.watchLogs": "ലോഗുകൾ കാണുക",
- "settings.server.webServer.updateServerIp": "സർവർ IP അപ്ഡേറ്റ് ചെയ്യുക",
- "settings.server.webServer.server.label": "സർവർ",
- "settings.server.webServer.traefik.label": "ട്രാഫിക്",
- "settings.server.webServer.traefik.modifyEnv": "ചുറ്റുപാടുകൾ മാറ്റുക",
- "settings.server.webServer.traefik.managePorts": "അധിക പോർട്ട് മാപ്പിംഗ്",
- "settings.server.webServer.traefik.managePortsDescription": "ട്രാഫിക്കിനായി അധിക പോർട്ടുകൾ ചേർക്കുക അല്ലെങ്കിൽ നീക്കം ചെയ്യുക",
- "settings.server.webServer.traefik.targetPort": "ടാർഗറ്റ് പോർട്ട്",
- "settings.server.webServer.traefik.publishedPort": "പ്രസിദ്ധീകരിച്ച പോർട്ട്",
- "settings.server.webServer.traefik.addPort": "പോർട്ട് ചേർക്കുക",
- "settings.server.webServer.traefik.portsUpdated": "പോർട്ടുകൾ വിജയകരമായി അപ്ഡേറ്റ് ചെയ്തു",
- "settings.server.webServer.traefik.portsUpdateError": "പോർട്ടുകൾ അപ്ഡേറ്റ് ചെയ്യാൻ പരാജയപ്പെട്ടു",
- "settings.server.webServer.traefik.publishMode": "പ്രസിദ്ധീകരണ മോഡ്",
- "settings.server.webServer.storage.label": "ഇടം",
- "settings.server.webServer.storage.cleanUnusedImages": "ഉപയോഗിക്കാത്ത ഇമേജുകൾ ശുചീകരിക്കുക",
- "settings.server.webServer.storage.cleanUnusedVolumes": "ഉപയോഗിക്കാത്ത വോള്യങ്ങൾ ശുചീകരിക്കുക",
- "settings.server.webServer.storage.cleanStoppedContainers": "നിർത്തിയ കണ്ടെയ്നറുകൾ ശുചീകരിക്കുക",
- "settings.server.webServer.storage.cleanDockerBuilder": "ഡോക്കർ ബിൽഡറും സിസ്റ്റവും ശുചീകരിക്കുക",
- "settings.server.webServer.storage.cleanMonitoring": "മോണിറ്ററിംഗ് ശുചീകരിക്കുക",
- "settings.server.webServer.storage.cleanAll": "എല്ലാം ശുചീകരിക്കുക",
-
- "settings.profile.title": "അക്കൗണ്ട്",
- "settings.profile.description": "നിങ്ങളുടെ പ്രൊഫൈൽ വിശദാംശങ്ങൾ ഇവിടെ മാറ്റുക.",
- "settings.profile.email": "ഇമെയിൽ",
- "settings.profile.password": "പാസ്വേഡ്",
- "settings.profile.avatar": "അവതാർ",
-
- "settings.appearance.title": "ദൃശ്യമാനം",
- "settings.appearance.description": "നിങ്ങളുടെ ഡാഷ്ബോർഡിന്റെ തീം ഇഷ്ടാനുസൃതമാക്കുക.",
- "settings.appearance.theme": "തീം",
- "settings.appearance.themeDescription": "നിങ്ങളുടെ ഡാഷ്ബോർഡിന് ഒരു തീം തിരഞ്ഞെടുക്കുക",
- "settings.appearance.themes.light": "ലൈറ്റ്",
- "settings.appearance.themes.dark": "ഡാർക്ക്",
- "settings.appearance.themes.system": "സിസ്റ്റം",
- "settings.appearance.language": "ഭാഷ",
- "settings.appearance.languageDescription": "നിങ്ങളുടെ ഡാഷ്ബോർഡിന് ഒരു ഭാഷ തിരഞ്ഞെടുക്കുക",
-
- "settings.terminal.connectionSettings": "കണക്ഷൻ ക്രമീകരണങ്ങൾ",
- "settings.terminal.ipAddress": "IP വിലാസം",
- "settings.terminal.port": "പോർട്ട്",
- "settings.terminal.username": "ഉപയോക്തൃനാമം"
-}
diff --git a/apps/dokploy/public/locales/ru/settings.json b/apps/dokploy/public/locales/ru/settings.json
index 0d87ed15..1e71d710 100644
--- a/apps/dokploy/public/locales/ru/settings.json
+++ b/apps/dokploy/public/locales/ru/settings.json
@@ -1,6 +1,5 @@
{
"settings.common.save": "Сохранить",
- "settings.common.enterTerminal": "Открыть терминал",
"settings.server.domain.title": "Домен сервера",
"settings.server.domain.description": "Установите домен для вашего серверного приложения Dokploy.",
"settings.server.domain.form.domain": "Домен",
@@ -8,26 +7,18 @@
"settings.server.domain.form.certificate.label": "Сертификат",
"settings.server.domain.form.certificate.placeholder": "Выберите сертификат",
"settings.server.domain.form.certificateOptions.none": "Нет",
- "settings.server.domain.form.certificateOptions.letsencrypt": "Let's Encrypt",
+ "settings.server.domain.form.certificateOptions.letsencrypt": "Let's Encrypt (По умолчанию)",
"settings.server.webServer.title": "Веб-сервер",
"settings.server.webServer.description": "Перезагрузка или очистка веб-сервера.",
+ "settings.server.webServer.server.label": "Сервер",
+ "settings.server.webServer.traefik.label": "Traefik",
+ "settings.server.webServer.storage.label": "Дисковое пространство",
"settings.server.webServer.actions": "Действия",
"settings.server.webServer.reload": "Перезагрузить",
"settings.server.webServer.watchLogs": "Просмотр логов",
"settings.server.webServer.updateServerIp": "Изменить IP адрес",
- "settings.server.webServer.server.label": "Сервер",
- "settings.server.webServer.traefik.label": "Traefik",
"settings.server.webServer.traefik.modifyEnv": "Изменить переменные окружения",
- "settings.server.webServer.traefik.managePorts": "Назначение портов",
- "settings.server.webServer.traefik.managePortsDescription": "Добавить или удалить дополнительные порты для Traefik",
- "settings.server.webServer.traefik.targetPort": "Внутренний порт",
- "settings.server.webServer.traefik.publishedPort": "Внешний порт",
- "settings.server.webServer.traefik.addPort": "Добавить порт",
- "settings.server.webServer.traefik.portsUpdated": "Порты успешно обновлены",
- "settings.server.webServer.traefik.portsUpdateError": "Не удалось обновить порты",
- "settings.server.webServer.traefik.publishMode": "Режим сопоставления",
- "settings.server.webServer.storage.label": "Дисковое пространство",
"settings.server.webServer.storage.cleanUnusedImages": "Очистить неиспользуемые образы",
"settings.server.webServer.storage.cleanUnusedVolumes": "Очистить неиспользуемые тома",
"settings.server.webServer.storage.cleanStoppedContainers": "Очистить остановленные контейнеры",
@@ -49,10 +40,5 @@
"settings.appearance.themes.dark": "Темная",
"settings.appearance.themes.system": "Системная",
"settings.appearance.language": "Язык",
- "settings.appearance.languageDescription": "Выберите язык для панели управления",
-
- "settings.terminal.connectionSettings": "Настройки подключения",
- "settings.terminal.ipAddress": "IP адрес",
- "settings.terminal.port": "Порт",
- "settings.terminal.username": "Имя пользователя"
+ "settings.appearance.languageDescription": "Select a language for your dashboard"
}
diff --git a/apps/dokploy/public/locales/uk/common.json b/apps/dokploy/public/locales/uk/common.json
deleted file mode 100644
index 0967ef42..00000000
--- a/apps/dokploy/public/locales/uk/common.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/apps/dokploy/public/locales/uk/settings.json b/apps/dokploy/public/locales/uk/settings.json
deleted file mode 100644
index 766a1bff..00000000
--- a/apps/dokploy/public/locales/uk/settings.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "settings.common.save": "Зберегти",
- "settings.common.enterTerminal": "Увійти в термінал",
- "settings.server.domain.title": "Домен сервера",
- "settings.server.domain.description": "Додайте домен до вашого серверного застосунку.",
- "settings.server.domain.form.domain": "Домен",
- "settings.server.domain.form.letsEncryptEmail": "Електронна пошта для Let's Encrypt",
- "settings.server.domain.form.certificate.label": "Постачальник сертифікатів",
- "settings.server.domain.form.certificate.placeholder": "Оберіть сертифікат",
- "settings.server.domain.form.certificateOptions.none": "Відсутній",
- "settings.server.domain.form.certificateOptions.letsencrypt": "Let's Encrypt",
-
- "settings.server.webServer.title": "Веб-сервер",
- "settings.server.webServer.description": "Перезавантажте або очистьте веб-сервер.",
- "settings.server.webServer.actions": "Дії",
- "settings.server.webServer.reload": "Перезавантажити",
- "settings.server.webServer.watchLogs": "Перегляд логів",
- "settings.server.webServer.updateServerIp": "Оновити IP-адресу сервера",
- "settings.server.webServer.server.label": "Сервер",
- "settings.server.webServer.traefik.label": "Traefik",
- "settings.server.webServer.traefik.modifyEnv": "Змінити середовище",
- "settings.server.webServer.traefik.managePorts": "Додаткові порти",
- "settings.server.webServer.traefik.managePortsDescription": "Додайте або видаліть порти для Traefik",
- "settings.server.webServer.traefik.targetPort": "Цільовий порт",
- "settings.server.webServer.traefik.publishedPort": "Опублікований порт",
- "settings.server.webServer.traefik.addPort": "Додати порт",
- "settings.server.webServer.traefik.portsUpdated": "Порти успішно оновлено",
- "settings.server.webServer.traefik.portsUpdateError": "Не вдалося оновити порти",
- "settings.server.webServer.traefik.publishMode": "Режим публікації",
- "settings.server.webServer.storage.label": "Дисковий простір",
- "settings.server.webServer.storage.cleanUnusedImages": "Очистити невикористані образи",
- "settings.server.webServer.storage.cleanUnusedVolumes": "Очистити невикористані томи",
- "settings.server.webServer.storage.cleanStoppedContainers": "Очистити зупинені контейнери",
- "settings.server.webServer.storage.cleanDockerBuilder": "Очистити Docker Builder і систему",
- "settings.server.webServer.storage.cleanMonitoring": "Очистити моніторинг",
- "settings.server.webServer.storage.cleanAll": "Очистити все",
-
- "settings.profile.title": "Обліковий запис",
- "settings.profile.description": "Змініть дані вашого профілю.",
- "settings.profile.email": "Електронна пошта",
- "settings.profile.password": "Пароль",
- "settings.profile.avatar": "Аватар",
-
- "settings.appearance.title": "Зовнішній вигляд",
- "settings.appearance.description": "Налаштуйте тему вашої панелі керування.",
- "settings.appearance.theme": "Тема",
- "settings.appearance.themeDescription": "Оберіть тему для вашої панелі керування",
- "settings.appearance.themes.light": "Світла",
- "settings.appearance.themes.dark": "Темна",
- "settings.appearance.themes.system": "Системна",
- "settings.appearance.language": "Мова",
- "settings.appearance.languageDescription": "Оберіть мову для вашої панелі керування",
-
- "settings.terminal.connectionSettings": "Налаштування з'єднання",
- "settings.terminal.ipAddress": "IP-адреса",
- "settings.terminal.port": "Порт",
- "settings.terminal.username": "Ім'я користувача"
-}
diff --git a/apps/dokploy/public/templates/alist.svg b/apps/dokploy/public/templates/alist.svg
deleted file mode 100644
index 37d5fdcd..00000000
--- a/apps/dokploy/public/templates/alist.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/apps/dokploy/public/templates/answer.png b/apps/dokploy/public/templates/answer.png
deleted file mode 100644
index 3fca604d..00000000
Binary files a/apps/dokploy/public/templates/answer.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/appwrite.svg b/apps/dokploy/public/templates/appwrite.svg
deleted file mode 100644
index 2034a812..00000000
--- a/apps/dokploy/public/templates/appwrite.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/apps/dokploy/public/templates/convex.svg b/apps/dokploy/public/templates/convex.svg
deleted file mode 100644
index 8622c4c0..00000000
--- a/apps/dokploy/public/templates/convex.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/apps/dokploy/public/templates/erpnext.svg b/apps/dokploy/public/templates/erpnext.svg
deleted file mode 100644
index d699ea2a..00000000
--- a/apps/dokploy/public/templates/erpnext.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/apps/dokploy/public/templates/evolutionapi.png b/apps/dokploy/public/templates/evolutionapi.png
deleted file mode 100644
index bd9b3850..00000000
Binary files a/apps/dokploy/public/templates/evolutionapi.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/formbricks.png b/apps/dokploy/public/templates/formbricks.png
deleted file mode 100644
index 2bf1ca1f..00000000
Binary files a/apps/dokploy/public/templates/formbricks.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/frappe-hr.svg b/apps/dokploy/public/templates/frappe-hr.svg
deleted file mode 100644
index 4cbf5164..00000000
--- a/apps/dokploy/public/templates/frappe-hr.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/apps/dokploy/public/templates/glance.png b/apps/dokploy/public/templates/glance.png
deleted file mode 100644
index 54fc4131..00000000
Binary files a/apps/dokploy/public/templates/glance.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/homarr.png b/apps/dokploy/public/templates/homarr.png
deleted file mode 100644
index 25581ea5..00000000
Binary files a/apps/dokploy/public/templates/homarr.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/linkwarden.png b/apps/dokploy/public/templates/linkwarden.png
deleted file mode 100644
index 843f681e..00000000
Binary files a/apps/dokploy/public/templates/linkwarden.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/mailpit.svg b/apps/dokploy/public/templates/mailpit.svg
deleted file mode 100644
index 58675a26..00000000
--- a/apps/dokploy/public/templates/mailpit.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/apps/dokploy/public/templates/maybe.svg b/apps/dokploy/public/templates/maybe.svg
deleted file mode 100644
index a4a87736..00000000
--- a/apps/dokploy/public/templates/maybe.svg
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/apps/dokploy/public/templates/outline.png b/apps/dokploy/public/templates/outline.png
deleted file mode 100644
index b241f01d..00000000
Binary files a/apps/dokploy/public/templates/outline.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/pocket-id.svg b/apps/dokploy/public/templates/pocket-id.svg
deleted file mode 100644
index 0ee89b14..00000000
--- a/apps/dokploy/public/templates/pocket-id.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/apps/dokploy/public/templates/registry.png b/apps/dokploy/public/templates/registry.png
deleted file mode 100644
index 39418022..00000000
Binary files a/apps/dokploy/public/templates/registry.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/shlink.svg b/apps/dokploy/public/templates/shlink.svg
deleted file mode 100644
index 6253cd36..00000000
--- a/apps/dokploy/public/templates/shlink.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/apps/dokploy/public/templates/spacedrive.png b/apps/dokploy/public/templates/spacedrive.png
deleted file mode 100644
index a10fffd5..00000000
Binary files a/apps/dokploy/public/templates/spacedrive.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/superset.svg b/apps/dokploy/public/templates/superset.svg
deleted file mode 100644
index 522c3b28..00000000
--- a/apps/dokploy/public/templates/superset.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Superset
-
-
-
-
-
-
diff --git a/apps/dokploy/public/templates/trilium.png b/apps/dokploy/public/templates/trilium.png
deleted file mode 100644
index f6afe82f..00000000
Binary files a/apps/dokploy/public/templates/trilium.png and /dev/null differ
diff --git a/apps/dokploy/public/templates/twenty.svg b/apps/dokploy/public/templates/twenty.svg
index bad18fab..cf5223b9 100644
--- a/apps/dokploy/public/templates/twenty.svg
+++ b/apps/dokploy/public/templates/twenty.svg
@@ -1,12 +1,6 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/apps/dokploy/public/templates/wikijs.svg b/apps/dokploy/public/templates/wikijs.svg
deleted file mode 100644
index 78073b23..00000000
--- a/apps/dokploy/public/templates/wikijs.svg
+++ /dev/null
@@ -1,119 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/apps/dokploy/reset-password.ts b/apps/dokploy/reset-password.ts
index 32cab433..43b11fdf 100644
--- a/apps/dokploy/reset-password.ts
+++ b/apps/dokploy/reset-password.ts
@@ -1,8 +1,6 @@
import { findAdmin } from "@dokploy/server";
+import { updateAuthById } from "@dokploy/server";
import { generateRandomPassword } from "@dokploy/server";
-import { db } from "@dokploy/server/db";
-import { account } from "@dokploy/server/db/schema";
-import { eq } from "drizzle-orm";
(async () => {
try {
@@ -10,12 +8,9 @@ import { eq } from "drizzle-orm";
const result = await findAdmin();
- const update = await db
- .update(account)
- .set({
- password: randomPassword.hashedPassword,
- })
- .where(eq(account.userId, result.userId));
+ const update = await updateAuthById(result.authId, {
+ password: randomPassword.hashedPassword,
+ });
if (update) {
console.log("Password reset successful");
diff --git a/apps/dokploy/server/api/root.ts b/apps/dokploy/server/api/root.ts
index 8120b319..6119ee85 100644
--- a/apps/dokploy/server/api/root.ts
+++ b/apps/dokploy/server/api/root.ts
@@ -20,7 +20,6 @@ import { mongoRouter } from "./routers/mongo";
import { mountRouter } from "./routers/mount";
import { mysqlRouter } from "./routers/mysql";
import { notificationRouter } from "./routers/notification";
-import { organizationRouter } from "./routers/organization";
import { portRouter } from "./routers/port";
import { postgresRouter } from "./routers/postgres";
import { previewDeploymentRouter } from "./routers/preview-deployment";
@@ -35,6 +34,7 @@ import { sshRouter } from "./routers/ssh-key";
import { stripeRouter } from "./routers/stripe";
import { swarmRouter } from "./routers/swarm";
import { userRouter } from "./routers/user";
+
/**
* This is the primary router for your server.
*
@@ -77,7 +77,6 @@ export const appRouter = createTRPCRouter({
stripe: stripeRouter,
swarm: swarmRouter,
ai: aiRouter,
- organization: organizationRouter,
});
// export type definition of API
diff --git a/apps/dokploy/server/api/routers/admin.ts b/apps/dokploy/server/api/routers/admin.ts
index 47bd9cd9..696f3c79 100644
--- a/apps/dokploy/server/api/routers/admin.ts
+++ b/apps/dokploy/server/api/routers/admin.ts
@@ -1,59 +1,103 @@
-import { apiUpdateWebServerMonitoring } from "@/server/db/schema";
+import { db } from "@/server/db";
import {
- IS_CLOUD,
+ apiAssignPermissions,
+ apiCreateUserInvitation,
+ apiFindOneToken,
+ apiRemoveUser,
+ apiUpdateAdmin,
+ users,
+} from "@/server/db/schema";
+import {
+ createInvitation,
+ findAdminById,
+ findUserByAuthId,
findUserById,
- setupWebMonitoring,
- updateUser,
+ getUserByToken,
+ removeUserByAuthId,
+ updateAdmin,
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
-import { adminProcedure, createTRPCRouter } from "../trpc";
+import { eq } from "drizzle-orm";
+import { adminProcedure, createTRPCRouter, publicProcedure } from "../trpc";
export const adminRouter = createTRPCRouter({
- setupMonitoring: adminProcedure
- .input(apiUpdateWebServerMonitoring)
+ one: adminProcedure.query(async ({ ctx }) => {
+ const { sshPrivateKey, ...rest } = await findAdminById(ctx.user.adminId);
+ return {
+ haveSSH: !!sshPrivateKey,
+ ...rest,
+ };
+ }),
+ update: adminProcedure
+ .input(apiUpdateAdmin)
+ .mutation(async ({ input, ctx }) => {
+ if (ctx.user.rol === "user") {
+ throw new TRPCError({
+ code: "UNAUTHORIZED",
+ message: "You are not allowed to update this admin",
+ });
+ }
+ const { authId } = await findAdminById(ctx.user.adminId);
+ return updateAdmin(authId, input);
+ }),
+ createUserInvitation: adminProcedure
+ .input(apiCreateUserInvitation)
.mutation(async ({ input, ctx }) => {
try {
- if (IS_CLOUD) {
- throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "Feature disabled on cloud",
- });
- }
- const user = await findUserById(ctx.user.ownerId);
- if (user.id !== ctx.user.ownerId) {
- throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "You are not authorized to setup the monitoring",
- });
- }
-
- await updateUser(user.id, {
- metricsConfig: {
- server: {
- type: "Dokploy",
- refreshRate: input.metricsConfig.server.refreshRate,
- port: input.metricsConfig.server.port,
- token: input.metricsConfig.server.token,
- cronJob: input.metricsConfig.server.cronJob,
- urlCallback: input.metricsConfig.server.urlCallback,
- retentionDays: input.metricsConfig.server.retentionDays,
- thresholds: {
- cpu: input.metricsConfig.server.thresholds.cpu,
- memory: input.metricsConfig.server.thresholds.memory,
- },
- },
- containers: {
- refreshRate: input.metricsConfig.containers.refreshRate,
- services: {
- include: input.metricsConfig.containers.services.include || [],
- exclude: input.metricsConfig.containers.services.exclude || [],
- },
- },
- },
+ await createInvitation(input, ctx.user.adminId);
+ } catch (error) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message:
+ "Error creating this user\ncheck if the email is not registered",
+ cause: error,
});
+ }
+ }),
+ removeUser: adminProcedure
+ .input(apiRemoveUser)
+ .mutation(async ({ input, ctx }) => {
+ try {
+ const user = await findUserByAuthId(input.authId);
- const currentServer = await setupWebMonitoring(user.id);
- return currentServer;
+ if (user.adminId !== ctx.user.adminId) {
+ throw new TRPCError({
+ code: "UNAUTHORIZED",
+ message: "You are not allowed to delete this user",
+ });
+ }
+ return await removeUserByAuthId(input.authId);
+ } catch (error) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Error deleting this user",
+ cause: error,
+ });
+ }
+ }),
+ getUserByToken: publicProcedure
+ .input(apiFindOneToken)
+ .query(async ({ input }) => {
+ return await getUserByToken(input.token);
+ }),
+ assignPermissions: adminProcedure
+ .input(apiAssignPermissions)
+ .mutation(async ({ input, ctx }) => {
+ try {
+ const user = await findUserById(input.userId);
+
+ if (user.adminId !== ctx.user.adminId) {
+ throw new TRPCError({
+ code: "UNAUTHORIZED",
+ message: "You are not allowed to assign permissions",
+ });
+ }
+ await db
+ .update(users)
+ .set({
+ ...input,
+ })
+ .where(eq(users.userId, input.userId));
} catch (error) {
throw error;
}
diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts
index e1629b4c..13b7c80d 100644
--- a/apps/dokploy/server/api/routers/application.ts
+++ b/apps/dokploy/server/api/routers/application.ts
@@ -60,13 +60,8 @@ export const applicationRouter = createTRPCRouter({
.input(apiCreateApplication)
.mutation(async ({ input, ctx }) => {
try {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.projectId,
- ctx.session.activeOrganizationId,
- "create",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.projectId, "create");
}
if (IS_CLOUD && !input.serverId) {
@@ -77,7 +72,7 @@ export const applicationRouter = createTRPCRouter({
}
const project = await findProjectById(input.projectId);
- if (project.organizationId !== ctx.session.activeOrganizationId) {
+ if (project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this project",
@@ -85,12 +80,8 @@ export const applicationRouter = createTRPCRouter({
}
const newApplication = await createApplication(input);
- if (ctx.user.rol === "member") {
- await addNewService(
- ctx.user.id,
- newApplication.applicationId,
- project.organizationId,
- );
+ if (ctx.user.rol === "user") {
+ await addNewService(ctx.user.authId, newApplication.applicationId);
}
return newApplication;
} catch (error: unknown) {
@@ -107,18 +98,15 @@ export const applicationRouter = createTRPCRouter({
one: protectedProcedure
.input(apiFindOneApplication)
.query(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
+ if (ctx.user.rol === "user") {
await checkServiceAccess(
- ctx.user.id,
+ ctx.user.authId,
input.applicationId,
- ctx.session.activeOrganizationId,
"access",
);
}
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -131,9 +119,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiReloadApplication)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to reload this application",
@@ -158,19 +144,16 @@ export const applicationRouter = createTRPCRouter({
delete: protectedProcedure
.input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
+ if (ctx.user.rol === "user") {
await checkServiceAccess(
- ctx.user.id,
+ ctx.user.authId,
input.applicationId,
- ctx.session.activeOrganizationId,
"delete",
);
}
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this application",
@@ -201,7 +184,7 @@ export const applicationRouter = createTRPCRouter({
for (const operation of cleanupOperations) {
try {
await operation();
- } catch (_) {}
+ } catch (error) {}
}
return result[0];
@@ -211,7 +194,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => {
const service = await findApplicationById(input.applicationId);
- if (service.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (service.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to stop this application",
@@ -231,7 +214,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => {
const service = await findApplicationById(input.applicationId);
- if (service.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (service.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to start this application",
@@ -252,9 +235,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to redeploy this application",
@@ -287,9 +268,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariables)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this environment",
@@ -305,9 +284,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveBuildType)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this build type",
@@ -328,9 +305,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveGithubProvider)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this github provider",
@@ -352,9 +327,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveGitlabProvider)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this gitlab provider",
@@ -378,9 +351,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveBitbucketProvider)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this bitbucket provider",
@@ -402,9 +373,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveDockerProvider)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this docker provider",
@@ -425,9 +394,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiSaveGitProvider)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this git provider",
@@ -448,9 +415,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to mark this application as running",
@@ -462,9 +427,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiUpdateApplication)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this application",
@@ -488,9 +451,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to refresh this application",
@@ -505,9 +466,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this application",
@@ -541,9 +500,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to clean this application",
@@ -556,9 +513,7 @@ export const applicationRouter = createTRPCRouter({
.input(apiFindOneApplication)
.query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to read this application",
@@ -593,7 +548,7 @@ export const applicationRouter = createTRPCRouter({
const app = await findApplicationById(input.applicationId as string);
- if (app.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (app.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this application",
@@ -635,9 +590,7 @@ export const applicationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this application",
@@ -657,7 +610,7 @@ export const applicationRouter = createTRPCRouter({
}),
readAppMonitoring: protectedProcedure
.input(apiFindMonitoringStats)
- .query(async ({ input }) => {
+ .query(async ({ input, ctx }) => {
if (IS_CLOUD) {
throw new TRPCError({
code: "UNAUTHORIZED",
diff --git a/apps/dokploy/server/api/routers/auth.ts b/apps/dokploy/server/api/routers/auth.ts
index 2c7469c3..f8bbfa9b 100644
--- a/apps/dokploy/server/api/routers/auth.ts
+++ b/apps/dokploy/server/api/routers/auth.ts
@@ -1,326 +1,523 @@
-import { createTRPCRouter } from "../trpc";
+import {
+ apiCreateAdmin,
+ apiCreateUser,
+ apiFindOneAuth,
+ apiLogin,
+ apiUpdateAuth,
+ apiVerify2FA,
+ apiVerifyLogin2FA,
+ auth,
+} from "@/server/db/schema";
+import { WEBSITE_URL } from "@/server/utils/stripe";
+import {
+ type Auth,
+ IS_CLOUD,
+ createAdmin,
+ createUser,
+ findAuthByEmail,
+ findAuthById,
+ generate2FASecret,
+ getUserByToken,
+ lucia,
+ luciaToken,
+ removeAdminByAuthId,
+ removeUserByAuthId,
+ sendDiscordNotification,
+ sendEmailNotification,
+ updateAuthById,
+ validateRequest,
+ verify2FA,
+} from "@dokploy/server";
+import { TRPCError } from "@trpc/server";
+import * as bcrypt from "bcrypt";
+import { isBefore } from "date-fns";
+import { eq } from "drizzle-orm";
+import { nanoid } from "nanoid";
+import { z } from "zod";
+import { db } from "../../db";
+import {
+ adminProcedure,
+ createTRPCRouter,
+ protectedProcedure,
+ publicProcedure,
+} from "../trpc";
export const authRouter = createTRPCRouter({
- // createAdmin: publicProcedure.mutation(async ({ input }) => {
- // try {
- // if (!IS_CLOUD) {
- // const admin = await db.query.admins.findFirst({});
- // if (admin) {
- // throw new TRPCError({
- // code: "BAD_REQUEST",
- // message: "Admin already exists",
- // });
- // }
- // }
- // const newAdmin = await createAdmin(input);
- // if (IS_CLOUD) {
- // await sendDiscordNotificationWelcome(newAdmin);
- // await sendVerificationEmail(newAdmin.id);
- // return {
- // status: "success",
- // type: "cloud",
- // };
- // }
- // // const session = await lucia.createSession(newAdmin.id || "", {});
- // // ctx.res.appendHeader(
- // // "Set-Cookie",
- // // lucia.createSessionCookie(session.id).serialize(),
- // // );
- // return {
- // status: "success",
- // type: "selfhosted",
- // };
- // } catch (error) {
- // throw new TRPCError({
- // code: "BAD_REQUEST",
- // // @ts-ignore
- // message: `Error: ${error?.code === "23505" ? "Email already exists" : "Error creating admin"}`,
- // cause: error,
- // });
- // }
- // }),
- // createUser: publicProcedure.mutation(async ({ input }) => {
- // try {
- // const _token = await getUserByToken(input.token);
- // // if (token.isExpired) {
- // // throw new TRPCError({
- // // code: "BAD_REQUEST",
- // // message: "Invalid token",
- // // });
- // // }
- // // const newUser = await createUser(input);
- // // if (IS_CLOUD) {
- // // await sendVerificationEmail(token.authId);
- // // return true;
- // // }
- // // const session = await lucia.createSession(newUser?.authId || "", {});
- // // ctx.res.appendHeader(
- // // "Set-Cookie",
- // // lucia.createSessionCookie(session.id).serialize(),
- // // );
- // return true;
- // } catch (error) {
- // throw new TRPCError({
- // code: "BAD_REQUEST",
- // message: "Error creating the user",
- // cause: error,
- // });
- // }
- // }),
- // login: publicProcedure.mutation(async ({ input }) => {
- // try {
- // const auth = await findAuthByEmail(input.email);
- // const correctPassword = bcrypt.compareSync(
- // input.password,
- // auth?.password || "",
- // );
- // if (!correctPassword) {
- // throw new TRPCError({
- // code: "BAD_REQUEST",
- // message: "Credentials do not match",
- // });
- // }
- // if (auth?.confirmationToken && IS_CLOUD) {
- // await sendVerificationEmail(auth.id);
- // throw new TRPCError({
- // code: "BAD_REQUEST",
- // message:
- // "Email not confirmed, we have sent you a confirmation email please check your inbox.",
- // });
- // }
- // if (auth?.is2FAEnabled) {
- // return {
- // is2FAEnabled: true,
- // authId: auth.id,
- // };
- // }
- // // const session = await lucia.createSession(auth?.id || "", {});
- // // ctx.res.appendHeader(
- // // "Set-Cookie",
- // // lucia.createSessionCookie(session.id).serialize(),
- // // );
- // return {
- // is2FAEnabled: false,
- // authId: auth?.id,
- // };
- // } catch (error) {
- // throw new TRPCError({
- // code: "BAD_REQUEST",
- // message: `Error: ${error instanceof Error ? error.message : "Login error"}`,
- // cause: error,
- // });
- // }
- // }),
- // get: protectedProcedure.query(async ({ ctx }) => {
- // const memberResult = await db.query.member.findFirst({
- // where: and(
- // eq(member.userId, ctx.user.id),
- // eq(member.organizationId, ctx.session?.activeOrganizationId || ""),
- // ),
- // with: {
- // user: true,
- // },
- // });
- // return memberResult;
- // }),
- // logout: protectedProcedure.mutation(async ({ ctx }) => {
- // const { req } = ctx;
- // const { session } = await validateRequest(req);
- // if (!session) return false;
- // // await lucia.invalidateSession(session.id);
- // // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize());
- // return true;
- // }),
- // update: protectedProcedure.mutation(async ({ ctx, input }) => {
- // const currentAuth = await findAuthByEmail(ctx.user.email);
- // if (input.currentPassword || input.password) {
- // const correctPassword = bcrypt.compareSync(
- // input.currentPassword || "",
- // currentAuth?.password || "",
- // );
- // if (!correctPassword) {
- // throw new TRPCError({
- // code: "BAD_REQUEST",
- // message: "Current password is incorrect",
- // });
- // }
- // }
- // // const auth = await updateAuthById(ctx.user.authId, {
- // // ...(input.email && { email: input.email.toLowerCase() }),
- // // ...(input.password && {
- // // password: bcrypt.hashSync(input.password, 10),
- // // }),
- // // ...(input.image && { image: input.image }),
- // // });
- // return auth;
- // }),
- // removeSelfAccount: protectedProcedure
- // .input(
- // z.object({
- // password: z.string().min(1),
- // }),
- // )
- // .mutation(async ({ ctx, input }) => {
- // if (!IS_CLOUD) {
- // throw new TRPCError({
- // code: "NOT_FOUND",
- // message: "This feature is only available in the cloud version",
- // });
- // }
- // const currentAuth = await findAuthByEmail(ctx.user.email);
- // const correctPassword = bcrypt.compareSync(
- // input.password,
- // currentAuth?.password || "",
- // );
- // if (!correctPassword) {
- // throw new TRPCError({
- // code: "BAD_REQUEST",
- // message: "Password is incorrect",
- // });
- // }
- // const { req } = ctx;
- // const { session } = await validateRequest(req);
- // if (!session) return false;
- // // await lucia.invalidateSession(session.id);
- // // res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize());
- // // if (ctx.user.rol === "owner") {
- // // await removeAdminByAuthId(ctx.user.authId);
- // // } else {
- // // await removeUserByAuthId(ctx.user.authId);
- // // }
- // return true;
- // }),
- // generateToken: protectedProcedure.mutation(async ({ ctx }) => {
- // const auth = await findUserById(ctx.user.id);
- // console.log(auth);
- // // if (auth.token) {
- // // await luciaToken.invalidateSession(auth.token);
- // // }
- // // const session = await luciaToken.createSession(auth?.id || "", {
- // // expiresIn: 60 * 60 * 24 * 30,
- // // });
- // // await updateUser(auth.id, {
- // // token: session.id,
- // // });
- // return auth;
- // }),
- // verifyToken: protectedProcedure.mutation(async () => {
- // return true;
- // }),
- // one: adminProcedure
- // .input(z.object({ userId: z.string().min(1) }))
- // .query(async ({ input }) => {
- // // TODO: Check if the user is admin or member
- // const user = await findUserById(input.userId);
- // return user;
- // }),
- // sendResetPasswordEmail: publicProcedure
- // .input(
- // z.object({
- // email: z.string().min(1).email(),
- // }),
- // )
- // .mutation(async ({ input }) => {
- // if (!IS_CLOUD) {
- // throw new TRPCError({
- // code: "NOT_FOUND",
- // message: "This feature is only available in the cloud version",
- // });
- // }
- // const authR = await db.query.auth.findFirst({
- // where: eq(auth.email, input.email),
- // });
- // if (!authR) {
- // throw new TRPCError({
- // code: "NOT_FOUND",
- // message: "User not found",
- // });
- // }
- // const token = nanoid();
- // await updateAuthById(authR.id, {
- // resetPasswordToken: token,
- // // Make resetPassword in 24 hours
- // resetPasswordExpiresAt: new Date(
- // new Date().getTime() + 24 * 60 * 60 * 1000,
- // ).toISOString(),
- // });
- // await sendEmailNotification(
- // {
- // fromAddress: process.env.SMTP_FROM_ADDRESS!,
- // toAddresses: [authR.email],
- // smtpServer: process.env.SMTP_SERVER!,
- // smtpPort: Number(process.env.SMTP_PORT),
- // username: process.env.SMTP_USERNAME!,
- // password: process.env.SMTP_PASSWORD!,
- // },
- // "Reset Password",
- // `
- // Reset your password by clicking the link below:
- // The link will expire in 24 hours.
- //
- // Reset Password
- //
- // `,
- // );
- // }),
+ createAdmin: publicProcedure
+ .input(apiCreateAdmin)
+ .mutation(async ({ ctx, input }) => {
+ try {
+ if (!IS_CLOUD) {
+ const admin = await db.query.admins.findFirst({});
+ if (admin) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Admin already exists",
+ });
+ }
+ }
+ const newAdmin = await createAdmin(input);
+
+ if (IS_CLOUD) {
+ await sendDiscordNotificationWelcome(newAdmin);
+ await sendVerificationEmail(newAdmin.id);
+ return {
+ status: "success",
+ type: "cloud",
+ };
+ }
+ const session = await lucia.createSession(newAdmin.id || "", {});
+ ctx.res.appendHeader(
+ "Set-Cookie",
+ lucia.createSessionCookie(session.id).serialize(),
+ );
+ return {
+ status: "success",
+ type: "selfhosted",
+ };
+ } catch (error) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ // @ts-ignore
+ message: `Error: ${error?.code === "23505" ? "Email already exists" : "Error creating admin"}`,
+ cause: error,
+ });
+ }
+ }),
+ createUser: publicProcedure
+ .input(apiCreateUser)
+ .mutation(async ({ ctx, input }) => {
+ try {
+ const token = await getUserByToken(input.token);
+ if (token.isExpired) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Invalid token",
+ });
+ }
+
+ const newUser = await createUser(input);
+
+ if (IS_CLOUD) {
+ await sendVerificationEmail(token.authId);
+ return true;
+ }
+ const session = await lucia.createSession(newUser?.authId || "", {});
+ ctx.res.appendHeader(
+ "Set-Cookie",
+ lucia.createSessionCookie(session.id).serialize(),
+ );
+ return true;
+ } catch (error) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Error creating the user",
+ cause: error,
+ });
+ }
+ }),
+
+ login: publicProcedure.input(apiLogin).mutation(async ({ ctx, input }) => {
+ try {
+ const auth = await findAuthByEmail(input.email);
+
+ const correctPassword = bcrypt.compareSync(
+ input.password,
+ auth?.password || "",
+ );
+
+ if (!correctPassword) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Credentials do not match",
+ });
+ }
+
+ if (auth?.confirmationToken && IS_CLOUD) {
+ await sendVerificationEmail(auth.id);
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message:
+ "Email not confirmed, we have sent you a confirmation email please check your inbox.",
+ });
+ }
+
+ if (auth?.is2FAEnabled) {
+ return {
+ is2FAEnabled: true,
+ authId: auth.id,
+ };
+ }
+
+ const session = await lucia.createSession(auth?.id || "", {});
+
+ ctx.res.appendHeader(
+ "Set-Cookie",
+ lucia.createSessionCookie(session.id).serialize(),
+ );
+ return {
+ is2FAEnabled: false,
+ authId: auth?.id,
+ };
+ } catch (error) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: `Error: ${error instanceof Error ? error.message : "Login error"}`,
+ cause: error,
+ });
+ }
+ }),
+
+ get: protectedProcedure.query(async ({ ctx }) => {
+ const auth = await findAuthById(ctx.user.authId);
+ return auth;
+ }),
+
+ logout: protectedProcedure.mutation(async ({ ctx }) => {
+ const { req, res } = ctx;
+ const { session } = await validateRequest(req, res);
+ if (!session) return false;
+
+ await lucia.invalidateSession(session.id);
+ res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize());
+ return true;
+ }),
+
+ update: protectedProcedure
+ .input(apiUpdateAuth)
+ .mutation(async ({ ctx, input }) => {
+ const currentAuth = await findAuthByEmail(ctx.user.email);
+
+ if (input.currentPassword || input.password) {
+ const correctPassword = bcrypt.compareSync(
+ input.currentPassword || "",
+ currentAuth?.password || "",
+ );
+ if (!correctPassword) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Current password is incorrect",
+ });
+ }
+ }
+ const auth = await updateAuthById(ctx.user.authId, {
+ ...(input.email && { email: input.email.toLowerCase() }),
+ ...(input.password && {
+ password: bcrypt.hashSync(input.password, 10),
+ }),
+ ...(input.image && { image: input.image }),
+ });
+
+ return auth;
+ }),
+ removeSelfAccount: protectedProcedure
+ .input(
+ z.object({
+ password: z.string().min(1),
+ }),
+ )
+ .mutation(async ({ ctx, input }) => {
+ if (!IS_CLOUD) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "This feature is only available in the cloud version",
+ });
+ }
+ const currentAuth = await findAuthByEmail(ctx.user.email);
+
+ const correctPassword = bcrypt.compareSync(
+ input.password,
+ currentAuth?.password || "",
+ );
+
+ if (!correctPassword) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Password is incorrect",
+ });
+ }
+ const { req, res } = ctx;
+ const { session } = await validateRequest(req, res);
+ if (!session) return false;
+
+ await lucia.invalidateSession(session.id);
+ res.setHeader("Set-Cookie", lucia.createBlankSessionCookie().serialize());
+
+ if (ctx.user.rol === "admin") {
+ await removeAdminByAuthId(ctx.user.authId);
+ } else {
+ await removeUserByAuthId(ctx.user.authId);
+ }
+
+ return true;
+ }),
+
+ generateToken: protectedProcedure.mutation(async ({ ctx, input }) => {
+ const auth = await findAuthById(ctx.user.authId);
+
+ if (auth.token) {
+ await luciaToken.invalidateSession(auth.token);
+ }
+ const session = await luciaToken.createSession(auth?.id || "", {
+ expiresIn: 60 * 60 * 24 * 30,
+ });
+
+ await updateAuthById(auth.id, {
+ token: session.id,
+ });
+
+ return auth;
+ }),
+ verifyToken: protectedProcedure.mutation(async () => {
+ return true;
+ }),
+ one: adminProcedure.input(apiFindOneAuth).query(async ({ input }) => {
+ const auth = await findAuthById(input.id);
+ return auth;
+ }),
+
+ generate2FASecret: protectedProcedure.query(async ({ ctx }) => {
+ return await generate2FASecret(ctx.user.authId);
+ }),
+ verify2FASetup: protectedProcedure
+ .input(apiVerify2FA)
+ .mutation(async ({ ctx, input }) => {
+ const auth = await findAuthById(ctx.user.authId);
+
+ await verify2FA(auth, input.secret, input.pin);
+ await updateAuthById(auth.id, {
+ is2FAEnabled: true,
+ secret: input.secret,
+ });
+ return auth;
+ }),
+
+ verifyLogin2FA: publicProcedure
+ .input(apiVerifyLogin2FA)
+ .mutation(async ({ ctx, input }) => {
+ const auth = await findAuthById(input.id);
+
+ await verify2FA(auth, auth.secret || "", input.pin);
+
+ const session = await lucia.createSession(auth.id, {});
+
+ ctx.res.appendHeader(
+ "Set-Cookie",
+ lucia.createSessionCookie(session.id).serialize(),
+ );
+
+ return true;
+ }),
+ disable2FA: protectedProcedure.mutation(async ({ ctx }) => {
+ const auth = await findAuthById(ctx.user.authId);
+ await updateAuthById(auth.id, {
+ is2FAEnabled: false,
+ secret: null,
+ });
+ return auth;
+ }),
+ sendResetPasswordEmail: publicProcedure
+ .input(
+ z.object({
+ email: z.string().min(1).email(),
+ }),
+ )
+ .mutation(async ({ ctx, input }) => {
+ if (!IS_CLOUD) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "This feature is only available in the cloud version",
+ });
+ }
+ const authR = await db.query.auth.findFirst({
+ where: eq(auth.email, input.email),
+ });
+ if (!authR) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "User not found",
+ });
+ }
+ const token = nanoid();
+ await updateAuthById(authR.id, {
+ resetPasswordToken: token,
+ // Make resetPassword in 24 hours
+ resetPasswordExpiresAt: new Date(
+ new Date().getTime() + 24 * 60 * 60 * 1000,
+ ).toISOString(),
+ });
+
+ await sendEmailNotification(
+ {
+ fromAddress: process.env.SMTP_FROM_ADDRESS!,
+ toAddresses: [authR.email],
+ smtpServer: process.env.SMTP_SERVER!,
+ smtpPort: Number(process.env.SMTP_PORT),
+ username: process.env.SMTP_USERNAME!,
+ password: process.env.SMTP_PASSWORD!,
+ },
+ "Reset Password",
+ `
+ Reset your password by clicking the link below:
+ The link will expire in 24 hours.
+
+ Reset Password
+
+
+ `,
+ );
+ }),
+
+ resetPassword: publicProcedure
+ .input(
+ z.object({
+ resetPasswordToken: z.string().min(1),
+ password: z.string().min(1),
+ }),
+ )
+ .mutation(async ({ ctx, input }) => {
+ if (!IS_CLOUD) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "This feature is only available in the cloud version",
+ });
+ }
+ const authR = await db.query.auth.findFirst({
+ where: eq(auth.resetPasswordToken, input.resetPasswordToken),
+ });
+
+ if (!authR || authR.resetPasswordExpiresAt === null) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Token not found",
+ });
+ }
+
+ const isExpired = isBefore(
+ new Date(authR.resetPasswordExpiresAt),
+ new Date(),
+ );
+
+ if (isExpired) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Token expired",
+ });
+ }
+
+ await updateAuthById(authR.id, {
+ resetPasswordExpiresAt: null,
+ resetPasswordToken: null,
+ password: bcrypt.hashSync(input.password, 10),
+ });
+
+ return true;
+ }),
+ confirmEmail: adminProcedure
+ .input(
+ z.object({
+ confirmationToken: z.string().min(1),
+ }),
+ )
+ .mutation(async ({ ctx, input }) => {
+ if (!IS_CLOUD) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Functionality not available in cloud version",
+ });
+ }
+ const authR = await db.query.auth.findFirst({
+ where: eq(auth.confirmationToken, input.confirmationToken),
+ });
+ if (!authR || authR.confirmationExpiresAt === null) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Token not found",
+ });
+ }
+ if (authR.confirmationToken !== input.confirmationToken) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Confirmation Token not found",
+ });
+ }
+
+ const isExpired = isBefore(
+ new Date(authR.confirmationExpiresAt),
+ new Date(),
+ );
+
+ if (isExpired) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Confirmation Token expired",
+ });
+ }
+ 1;
+ await updateAuthById(authR.id, {
+ confirmationToken: null,
+ confirmationExpiresAt: null,
+ });
+ return true;
+ }),
});
-// export const sendVerificationEmail = async (authId: string) => {
-// const token = nanoid();
-// const result = await updateAuthById(authId, {
-// confirmationToken: token,
-// confirmationExpiresAt: new Date(
-// new Date().getTime() + 24 * 60 * 60 * 1000,
-// ).toISOString(),
-// });
+export const sendVerificationEmail = async (authId: string) => {
+ const token = nanoid();
+ const result = await updateAuthById(authId, {
+ confirmationToken: token,
+ confirmationExpiresAt: new Date(
+ new Date().getTime() + 24 * 60 * 60 * 1000,
+ ).toISOString(),
+ });
-// if (!result) {
-// throw new TRPCError({
-// code: "BAD_REQUEST",
-// message: "User not found",
-// });
-// }
-// await sendEmailNotification(
-// {
-// fromAddress: process.env.SMTP_FROM_ADDRESS || "",
-// toAddresses: [result?.email],
-// smtpServer: process.env.SMTP_SERVER || "",
-// smtpPort: Number(process.env.SMTP_PORT),
-// username: process.env.SMTP_USERNAME || "",
-// password: process.env.SMTP_PASSWORD || "",
-// },
-// "Confirm your email | Dokploy",
-// `
-// Welcome to Dokploy!
-// Please confirm your email by clicking the link below:
-//
-// Confirm Email
-//
-// `,
-// );
+ if (!result) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "User not found",
+ });
+ }
+ await sendEmailNotification(
+ {
+ fromAddress: process.env.SMTP_FROM_ADDRESS || "",
+ toAddresses: [result?.email],
+ smtpServer: process.env.SMTP_SERVER || "",
+ smtpPort: Number(process.env.SMTP_PORT),
+ username: process.env.SMTP_USERNAME || "",
+ password: process.env.SMTP_PASSWORD || "",
+ },
+ "Confirm your email | Dokploy",
+ `
+ Welcome to Dokploy!
+ Please confirm your email by clicking the link below:
+
+ Confirm Email
+
+ `,
+ );
-// return true;
-// };
+ return true;
+};
-// export const sendDiscordNotificationWelcome = async (newAdmin: Auth) => {
-// await sendDiscordNotification(
-// {
-// webhookUrl: process.env.DISCORD_WEBHOOK_URL || "",
-// },
-// {
-// title: "New User Registered",
-// color: 0x00ff00,
-// fields: [
-// {
-// name: "Email",
-// value: newAdmin.email,
-// inline: true,
-// },
-// ],
-// timestamp: newAdmin.createdAt,
-// footer: {
-// text: "Dokploy User Registration Notification",
-// },
-// },
-// );
-// };
+export const sendDiscordNotificationWelcome = async (newAdmin: Auth) => {
+ await sendDiscordNotification(
+ {
+ webhookUrl: process.env.DISCORD_WEBHOOK_URL || "",
+ },
+ {
+ title: "New User Registered",
+ color: 0x00ff00,
+ fields: [
+ {
+ name: "Email",
+ value: newAdmin.email,
+ inline: true,
+ },
+ ],
+ timestamp: newAdmin.createdAt,
+ footer: {
+ text: "Dokploy User Registration Notification",
+ },
+ },
+ );
+};
diff --git a/apps/dokploy/server/api/routers/backup.ts b/apps/dokploy/server/api/routers/backup.ts
index 8a7a5f22..0b8d7ab1 100644
--- a/apps/dokploy/server/api/routers/backup.ts
+++ b/apps/dokploy/server/api/routers/backup.ts
@@ -30,7 +30,7 @@ import { TRPCError } from "@trpc/server";
export const backupRouter = createTRPCRouter({
create: protectedProcedure
.input(apiCreateBackup)
- .mutation(async ({ input }) => {
+ .mutation(async ({ input, ctx }) => {
try {
const newBackup = await createBackup(input);
@@ -74,14 +74,16 @@ export const backupRouter = createTRPCRouter({
});
}
}),
- one: protectedProcedure.input(apiFindOneBackup).query(async ({ input }) => {
- const backup = await findBackupById(input.backupId);
+ one: protectedProcedure
+ .input(apiFindOneBackup)
+ .query(async ({ input, ctx }) => {
+ const backup = await findBackupById(input.backupId);
- return backup;
- }),
+ return backup;
+ }),
update: protectedProcedure
.input(apiUpdateBackup)
- .mutation(async ({ input }) => {
+ .mutation(async ({ input, ctx }) => {
try {
await updateBackupById(input.backupId, input);
const backup = await findBackupById(input.backupId);
@@ -109,17 +111,15 @@ export const backupRouter = createTRPCRouter({
}
}
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error updating this Backup";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error updating this Backup",
});
}
}),
remove: protectedProcedure
.input(apiRemoveBackup)
- .mutation(async ({ input }) => {
+ .mutation(async ({ input, ctx }) => {
try {
const value = await removeBackupById(input.backupId);
if (IS_CLOUD && value) {
@@ -133,11 +133,10 @@ export const backupRouter = createTRPCRouter({
}
return value;
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error deleting this Backup";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error deleting this Backup",
+ cause: error,
});
}
}),
@@ -150,13 +149,11 @@ export const backupRouter = createTRPCRouter({
await runPostgresBackup(postgres, backup);
return true;
} catch (error) {
- const message =
- error instanceof Error
- ? error.message
- : "Error running manual Postgres backup ";
+ console.log(error);
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error running manual Postgres backup ",
+ cause: error,
});
}
}),
diff --git a/apps/dokploy/server/api/routers/bitbucket.ts b/apps/dokploy/server/api/routers/bitbucket.ts
index fa02be8d..c66716d3 100644
--- a/apps/dokploy/server/api/routers/bitbucket.ts
+++ b/apps/dokploy/server/api/routers/bitbucket.ts
@@ -8,6 +8,7 @@ import {
apiUpdateBitbucket,
} from "@/server/db/schema";
import {
+ IS_CLOUD,
createBitbucket,
findBitbucketById,
getBitbucketBranches,
@@ -22,7 +23,7 @@ export const bitbucketRouter = createTRPCRouter({
.input(apiCreateBitbucket)
.mutation(async ({ input, ctx }) => {
try {
- return await createBitbucket(input, ctx.session.activeOrganizationId);
+ return await createBitbucket(input, ctx.user.adminId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
@@ -36,9 +37,10 @@ export const bitbucketRouter = createTRPCRouter({
.query(async ({ input, ctx }) => {
const bitbucketProvider = await findBitbucketById(input.bitbucketId);
if (
- bitbucketProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
+ IS_CLOUD &&
+ bitbucketProvider.gitProvider.adminId !== ctx.user.adminId
) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this bitbucket provider",
@@ -56,11 +58,12 @@ export const bitbucketRouter = createTRPCRouter({
},
});
- result = result.filter(
- (provider) =>
- provider.gitProvider.organizationId ===
- ctx.session.activeOrganizationId,
- );
+ if (IS_CLOUD) {
+ // TODO: mAyBe a rEfaCtoR 🤫
+ result = result.filter(
+ (provider) => provider.gitProvider.adminId === ctx.user.adminId,
+ );
+ }
return result;
}),
@@ -69,9 +72,10 @@ export const bitbucketRouter = createTRPCRouter({
.query(async ({ input, ctx }) => {
const bitbucketProvider = await findBitbucketById(input.bitbucketId);
if (
- bitbucketProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
+ IS_CLOUD &&
+ bitbucketProvider.gitProvider.adminId !== ctx.user.adminId
) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this bitbucket provider",
@@ -86,9 +90,10 @@ export const bitbucketRouter = createTRPCRouter({
input.bitbucketId || "",
);
if (
- bitbucketProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
+ IS_CLOUD &&
+ bitbucketProvider.gitProvider.adminId !== ctx.user.adminId
) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this bitbucket provider",
@@ -102,9 +107,10 @@ export const bitbucketRouter = createTRPCRouter({
try {
const bitbucketProvider = await findBitbucketById(input.bitbucketId);
if (
- bitbucketProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
+ IS_CLOUD &&
+ bitbucketProvider.gitProvider.adminId !== ctx.user.adminId
) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this bitbucket provider",
@@ -125,9 +131,10 @@ export const bitbucketRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const bitbucketProvider = await findBitbucketById(input.bitbucketId);
if (
- bitbucketProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
+ IS_CLOUD &&
+ bitbucketProvider.gitProvider.adminId !== ctx.user.adminId
) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this bitbucket provider",
@@ -135,7 +142,7 @@ export const bitbucketRouter = createTRPCRouter({
}
return await updateBitbucket(input.bitbucketId, {
...input,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
}),
});
diff --git a/apps/dokploy/server/api/routers/certificate.ts b/apps/dokploy/server/api/routers/certificate.ts
index 3dc944ac..0f8d6fd9 100644
--- a/apps/dokploy/server/api/routers/certificate.ts
+++ b/apps/dokploy/server/api/routers/certificate.ts
@@ -25,14 +25,14 @@ export const certificateRouter = createTRPCRouter({
message: "Please set a server to create a certificate",
});
}
- return await createCertificate(input, ctx.session.activeOrganizationId);
+ return await createCertificate(input, ctx.user.adminId);
}),
one: adminProcedure
.input(apiFindCertificate)
.query(async ({ input, ctx }) => {
const certificates = await findCertificateById(input.certificateId);
- if (certificates.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && certificates.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this certificate",
@@ -44,7 +44,7 @@ export const certificateRouter = createTRPCRouter({
.input(apiFindCertificate)
.mutation(async ({ input, ctx }) => {
const certificates = await findCertificateById(input.certificateId);
- if (certificates.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && certificates.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to delete this certificate",
@@ -55,7 +55,8 @@ export const certificateRouter = createTRPCRouter({
}),
all: adminProcedure.query(async ({ ctx }) => {
return await db.query.certificates.findMany({
- where: eq(certificates.organizationId, ctx.session.activeOrganizationId),
+ // TODO: Remove this line when the cloud version is ready
+ ...(IS_CLOUD && { where: eq(certificates.adminId, ctx.user.adminId) }),
});
}),
});
diff --git a/apps/dokploy/server/api/routers/cluster.ts b/apps/dokploy/server/api/routers/cluster.ts
index 0d840757..7ded632c 100644
--- a/apps/dokploy/server/api/routers/cluster.ts
+++ b/apps/dokploy/server/api/routers/cluster.ts
@@ -40,7 +40,7 @@ export const clusterRouter = createTRPCRouter({
});
}
}),
- addWorker: protectedProcedure.query(async () => {
+ addWorker: protectedProcedure.query(async ({ input }) => {
if (IS_CLOUD) {
return {
command: "",
@@ -57,7 +57,7 @@ export const clusterRouter = createTRPCRouter({
version: docker_version.Version,
};
}),
- addManager: protectedProcedure.query(async () => {
+ addManager: protectedProcedure.query(async ({ input }) => {
if (IS_CLOUD) {
return {
command: "",
diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts
index bae926d0..dab37e78 100644
--- a/apps/dokploy/server/api/routers/compose.ts
+++ b/apps/dokploy/server/api/routers/compose.ts
@@ -39,14 +39,13 @@ import {
createComposeByTemplate,
createDomain,
createMount,
+ findAdminById,
findComposeById,
findDomainsByComposeId,
findProjectById,
findServerById,
- findUserById,
loadServices,
randomizeComposeFile,
- randomizeIsolatedDeploymentComposeFile,
removeCompose,
removeComposeDirectory,
removeDeploymentsByComposeId,
@@ -60,13 +59,8 @@ export const composeRouter = createTRPCRouter({
.input(apiCreateCompose)
.mutation(async ({ ctx, input }) => {
try {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.projectId,
- ctx.session.activeOrganizationId,
- "create",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.projectId, "create");
}
if (IS_CLOUD && !input.serverId) {
@@ -76,7 +70,7 @@ export const composeRouter = createTRPCRouter({
});
}
const project = await findProjectById(input.projectId);
- if (project.organizationId !== ctx.session.activeOrganizationId) {
+ if (project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this project",
@@ -84,12 +78,8 @@ export const composeRouter = createTRPCRouter({
}
const newService = await createCompose(input);
- if (ctx.user.rol === "member") {
- await addNewService(
- ctx.user.id,
- newService.composeId,
- project.organizationId,
- );
+ if (ctx.user.rol === "user") {
+ await addNewService(ctx.user.authId, newService.composeId);
}
return newService;
@@ -101,17 +91,12 @@ export const composeRouter = createTRPCRouter({
one: protectedProcedure
.input(apiFindCompose)
.query(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.composeId,
- ctx.session.activeOrganizationId,
- "access",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.composeId, "access");
}
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
@@ -124,7 +109,7 @@ export const composeRouter = createTRPCRouter({
.input(apiUpdateCompose)
.mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this compose",
@@ -135,20 +120,12 @@ export const composeRouter = createTRPCRouter({
delete: protectedProcedure
.input(apiDeleteCompose)
.mutation(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.composeId,
- ctx.session.activeOrganizationId,
- "delete",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.composeId, "delete");
}
const composeResult = await findComposeById(input.composeId);
- if (
- composeResult.project.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (composeResult.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this compose",
@@ -170,7 +147,7 @@ export const composeRouter = createTRPCRouter({
for (const operation of cleanupOperations) {
try {
await operation();
- } catch (_) {}
+ } catch (error) {}
}
return result[0];
@@ -179,7 +156,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose)
.mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to clean this compose",
@@ -192,7 +169,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFetchServices)
.query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to load this compose",
@@ -206,9 +183,7 @@ export const composeRouter = createTRPCRouter({
try {
const compose = await findComposeById(input.composeId);
- if (
- compose.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to fetch this compose",
@@ -233,7 +208,7 @@ export const composeRouter = createTRPCRouter({
.input(apiRandomizeCompose)
.mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to randomize this compose",
@@ -241,26 +216,11 @@ export const composeRouter = createTRPCRouter({
}
return await randomizeComposeFile(input.composeId, input.suffix);
}),
- isolatedDeployment: protectedProcedure
- .input(apiRandomizeCompose)
- .mutation(async ({ input, ctx }) => {
- const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
- throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "You are not authorized to randomize this compose",
- });
- }
- return await randomizeIsolatedDeploymentComposeFile(
- input.composeId,
- input.suffix,
- );
- }),
getConvertedCompose: protectedProcedure
.input(apiFindCompose)
.query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to get this compose",
@@ -278,7 +238,7 @@ export const composeRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this compose",
@@ -311,7 +271,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose)
.mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to redeploy this compose",
@@ -343,7 +303,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose)
.mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to stop this compose",
@@ -357,7 +317,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose)
.mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to stop this compose",
@@ -372,7 +332,7 @@ export const composeRouter = createTRPCRouter({
.query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to get this compose",
@@ -385,7 +345,7 @@ export const composeRouter = createTRPCRouter({
.input(apiFindCompose)
.mutation(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to refresh this compose",
@@ -399,13 +359,8 @@ export const composeRouter = createTRPCRouter({
deployTemplate: protectedProcedure
.input(apiCreateComposeByTemplate)
.mutation(async ({ ctx, input }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.projectId,
- ctx.session.activeOrganizationId,
- "create",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.projectId, "create");
}
if (IS_CLOUD && !input.serverId) {
@@ -419,7 +374,7 @@ export const composeRouter = createTRPCRouter({
const generate = await loadTemplateModule(input.id as TemplatesKeys);
- const admin = await findUserById(ctx.user.ownerId);
+ const admin = await findAdminById(ctx.user.adminId);
let serverIp = admin.serverIp || "127.0.0.1";
const project = await findProjectById(input.projectId);
@@ -444,15 +399,10 @@ export const composeRouter = createTRPCRouter({
name: input.id,
sourceType: "raw",
appName: `${projectName}-${generatePassword(6)}`,
- isolatedDeployment: true,
});
- if (ctx.user.rol === "member") {
- await addNewService(
- ctx.user.id,
- compose.composeId,
- project.organizationId,
- );
+ if (ctx.user.rol === "user") {
+ await addNewService(ctx.user.authId, compose.composeId);
}
if (mounts && mounts?.length > 0) {
@@ -496,7 +446,7 @@ export const composeRouter = createTRPCRouter({
return templatesData;
}),
- getTags: protectedProcedure.query(async () => {
+ getTags: protectedProcedure.query(async ({ input }) => {
const allTags = templates.flatMap((template) => template.tags);
const uniqueTags = _.uniq(allTags);
return uniqueTags;
diff --git a/apps/dokploy/server/api/routers/deployment.ts b/apps/dokploy/server/api/routers/deployment.ts
index 8d95c121..bf981c6d 100644
--- a/apps/dokploy/server/api/routers/deployment.ts
+++ b/apps/dokploy/server/api/routers/deployment.ts
@@ -19,9 +19,7 @@ export const deploymentRouter = createTRPCRouter({
.input(apiFindAllByApplication)
.query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -34,7 +32,7 @@ export const deploymentRouter = createTRPCRouter({
.input(apiFindAllByCompose)
.query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
@@ -46,7 +44,7 @@ export const deploymentRouter = createTRPCRouter({
.input(apiFindAllByServer)
.query(async ({ input, ctx }) => {
const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session.activeOrganizationId) {
+ if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this server",
diff --git a/apps/dokploy/server/api/routers/destination.ts b/apps/dokploy/server/api/routers/destination.ts
index f1d582c5..d13928be 100644
--- a/apps/dokploy/server/api/routers/destination.ts
+++ b/apps/dokploy/server/api/routers/destination.ts
@@ -28,10 +28,7 @@ export const destinationRouter = createTRPCRouter({
.input(apiCreateDestination)
.mutation(async ({ input, ctx }) => {
try {
- return await createDestintation(
- input,
- ctx.session.activeOrganizationId,
- );
+ return await createDestintation(input, ctx.user.adminId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
@@ -87,7 +84,7 @@ export const destinationRouter = createTRPCRouter({
.input(apiFindOneDestination)
.query(async ({ input, ctx }) => {
const destination = await findDestinationById(input.destinationId);
- if (destination.organizationId !== ctx.session.activeOrganizationId) {
+ if (destination.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this destination",
@@ -97,7 +94,7 @@ export const destinationRouter = createTRPCRouter({
}),
all: protectedProcedure.query(async ({ ctx }) => {
return await db.query.destinations.findMany({
- where: eq(destinations.organizationId, ctx.session.activeOrganizationId),
+ where: eq(destinations.adminId, ctx.user.adminId),
});
}),
remove: adminProcedure
@@ -106,7 +103,7 @@ export const destinationRouter = createTRPCRouter({
try {
const destination = await findDestinationById(input.destinationId);
- if (destination.organizationId !== ctx.session.activeOrganizationId) {
+ if (destination.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to delete this destination",
@@ -114,7 +111,7 @@ export const destinationRouter = createTRPCRouter({
}
return await removeDestinationById(
input.destinationId,
- ctx.session.activeOrganizationId,
+ ctx.user.adminId,
);
} catch (error) {
throw error;
@@ -125,7 +122,7 @@ export const destinationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const destination = await findDestinationById(input.destinationId);
- if (destination.organizationId !== ctx.session.activeOrganizationId) {
+ if (destination.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to update this destination",
@@ -133,7 +130,7 @@ export const destinationRouter = createTRPCRouter({
}
return await updateDestinationById(input.destinationId, {
...input,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
} catch (error) {
throw error;
diff --git a/apps/dokploy/server/api/routers/domain.ts b/apps/dokploy/server/api/routers/domain.ts
index aac2a016..f122cf86 100644
--- a/apps/dokploy/server/api/routers/domain.ts
+++ b/apps/dokploy/server/api/routers/domain.ts
@@ -30,9 +30,7 @@ export const domainRouter = createTRPCRouter({
try {
if (input.domainType === "compose" && input.composeId) {
const compose = await findComposeById(input.composeId);
- if (
- compose.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
@@ -40,10 +38,7 @@ export const domainRouter = createTRPCRouter({
}
} else if (input.domainType === "application" && input.applicationId) {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -63,9 +58,7 @@ export const domainRouter = createTRPCRouter({
.input(apiFindOneApplication)
.query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -77,7 +70,7 @@ export const domainRouter = createTRPCRouter({
.input(apiFindCompose)
.query(async ({ input, ctx }) => {
const compose = await findComposeById(input.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
@@ -90,7 +83,7 @@ export const domainRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
return generateTraefikMeDomain(
input.appName,
- ctx.user.ownerId,
+ ctx.user.adminId,
input.serverId,
);
}),
@@ -102,9 +95,7 @@ export const domainRouter = createTRPCRouter({
if (currentDomain.applicationId) {
const newApp = await findApplicationById(currentDomain.applicationId);
- if (
- newApp.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (newApp.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -112,9 +103,7 @@ export const domainRouter = createTRPCRouter({
}
} else if (currentDomain.composeId) {
const newCompose = await findComposeById(currentDomain.composeId);
- if (
- newCompose.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (newCompose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
@@ -125,8 +114,7 @@ export const domainRouter = createTRPCRouter({
currentDomain.previewDeploymentId,
);
if (
- newPreviewDeployment.application.project.organizationId !==
- ctx.session.activeOrganizationId
+ newPreviewDeployment.application.project.adminId !== ctx.user.adminId
) {
throw new TRPCError({
code: "UNAUTHORIZED",
@@ -155,9 +143,7 @@ export const domainRouter = createTRPCRouter({
const domain = await findDomainById(input.domainId);
if (domain.applicationId) {
const application = await findApplicationById(domain.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -165,7 +151,7 @@ export const domainRouter = createTRPCRouter({
}
} else if (domain.composeId) {
const compose = await findComposeById(domain.composeId);
- if (compose.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
@@ -180,10 +166,7 @@ export const domainRouter = createTRPCRouter({
const domain = await findDomainById(input.domainId);
if (domain.applicationId) {
const application = await findApplicationById(domain.applicationId);
- if (
- application.project.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -191,9 +174,7 @@ export const domainRouter = createTRPCRouter({
}
} else if (domain.composeId) {
const compose = await findComposeById(domain.composeId);
- if (
- compose.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (compose.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this compose",
diff --git a/apps/dokploy/server/api/routers/git-provider.ts b/apps/dokploy/server/api/routers/git-provider.ts
index ed37869d..abd93392 100644
--- a/apps/dokploy/server/api/routers/git-provider.ts
+++ b/apps/dokploy/server/api/routers/git-provider.ts
@@ -1,7 +1,11 @@
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
import { db } from "@/server/db";
import { apiRemoveGitProvider, gitProvider } from "@/server/db/schema";
-import { findGitProviderById, removeGitProvider } from "@dokploy/server";
+import {
+ IS_CLOUD,
+ findGitProviderById,
+ removeGitProvider,
+} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
import { desc, eq } from "drizzle-orm";
@@ -14,7 +18,8 @@ export const gitProviderRouter = createTRPCRouter({
github: true,
},
orderBy: desc(gitProvider.createdAt),
- where: eq(gitProvider.organizationId, ctx.session.activeOrganizationId),
+ ...(IS_CLOUD && { where: eq(gitProvider.adminId, ctx.user.adminId) }),
+ //TODO: Remove this line when the cloud version is ready
});
}),
remove: protectedProcedure
@@ -23,7 +28,8 @@ export const gitProviderRouter = createTRPCRouter({
try {
const gitProvider = await findGitProviderById(input.gitProviderId);
- if (gitProvider.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && gitProvider.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to delete this Git provider",
@@ -31,13 +37,9 @@ export const gitProviderRouter = createTRPCRouter({
}
return await removeGitProvider(input.gitProviderId);
} catch (error) {
- const message =
- error instanceof Error
- ? error.message
- : "Error deleting this Git provider";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error deleting this Git provider",
});
}
}),
diff --git a/apps/dokploy/server/api/routers/github.ts b/apps/dokploy/server/api/routers/github.ts
index 691030e2..56222577 100644
--- a/apps/dokploy/server/api/routers/github.ts
+++ b/apps/dokploy/server/api/routers/github.ts
@@ -6,6 +6,7 @@ import {
apiUpdateGithub,
} from "@/server/db/schema";
import {
+ IS_CLOUD,
findGithubById,
getGithubBranches,
getGithubRepositories,
@@ -19,10 +20,8 @@ export const githubRouter = createTRPCRouter({
.input(apiFindOneGithub)
.query(async ({ input, ctx }) => {
const githubProvider = await findGithubById(input.githubId);
- if (
- githubProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this github provider",
@@ -34,10 +33,8 @@ export const githubRouter = createTRPCRouter({
.input(apiFindOneGithub)
.query(async ({ input, ctx }) => {
const githubProvider = await findGithubById(input.githubId);
- if (
- githubProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this github provider",
@@ -49,10 +46,7 @@ export const githubRouter = createTRPCRouter({
.input(apiFindGithubBranches)
.query(async ({ input, ctx }) => {
const githubProvider = await findGithubById(input.githubId || "");
- if (
- githubProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) {
//TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
@@ -68,11 +62,12 @@ export const githubRouter = createTRPCRouter({
},
});
- result = result.filter(
- (provider) =>
- provider.gitProvider.organizationId ===
- ctx.session.activeOrganizationId,
- );
+ if (IS_CLOUD) {
+ // TODO: mAyBe a rEfaCtoR 🤫
+ result = result.filter(
+ (provider) => provider.gitProvider.adminId === ctx.user.adminId,
+ );
+ }
const filtered = result
.filter((provider) => haveGithubRequirements(provider))
@@ -94,9 +89,10 @@ export const githubRouter = createTRPCRouter({
try {
const githubProvider = await findGithubById(input.githubId);
if (
- githubProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
+ IS_CLOUD &&
+ githubProvider.gitProvider.adminId !== ctx.user.adminId
) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this github provider",
@@ -115,10 +111,8 @@ export const githubRouter = createTRPCRouter({
.input(apiUpdateGithub)
.mutation(async ({ input, ctx }) => {
const githubProvider = await findGithubById(input.githubId);
- if (
- githubProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (IS_CLOUD && githubProvider.gitProvider.adminId !== ctx.user.adminId) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this github provider",
@@ -126,7 +120,7 @@ export const githubRouter = createTRPCRouter({
}
await updateGitProvider(input.gitProviderId, {
name: input.name,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
}),
});
diff --git a/apps/dokploy/server/api/routers/gitlab.ts b/apps/dokploy/server/api/routers/gitlab.ts
index daae68a5..6d35f4a2 100644
--- a/apps/dokploy/server/api/routers/gitlab.ts
+++ b/apps/dokploy/server/api/routers/gitlab.ts
@@ -9,6 +9,7 @@ import {
import { db } from "@/server/db";
import {
+ IS_CLOUD,
createGitlab,
findGitlabById,
getGitlabBranches,
@@ -25,7 +26,7 @@ export const gitlabRouter = createTRPCRouter({
.input(apiCreateGitlab)
.mutation(async ({ input, ctx }) => {
try {
- return await createGitlab(input, ctx.session.activeOrganizationId);
+ return await createGitlab(input, ctx.user.adminId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
@@ -38,10 +39,8 @@ export const gitlabRouter = createTRPCRouter({
.input(apiFindOneGitlab)
.query(async ({ input, ctx }) => {
const gitlabProvider = await findGitlabById(input.gitlabId);
- if (
- gitlabProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this Gitlab provider",
@@ -56,11 +55,12 @@ export const gitlabRouter = createTRPCRouter({
},
});
- result = result.filter(
- (provider) =>
- provider.gitProvider.organizationId ===
- ctx.session.activeOrganizationId,
- );
+ if (IS_CLOUD) {
+ // TODO: mAyBe a rEfaCtoR 🤫
+ result = result.filter(
+ (provider) => provider.gitProvider.adminId === ctx.user.adminId,
+ );
+ }
const filtered = result
.filter((provider) => haveGitlabRequirements(provider))
.map((provider) => {
@@ -78,10 +78,8 @@ export const gitlabRouter = createTRPCRouter({
.input(apiFindOneGitlab)
.query(async ({ input, ctx }) => {
const gitlabProvider = await findGitlabById(input.gitlabId);
- if (
- gitlabProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this Gitlab provider",
@@ -94,10 +92,8 @@ export const gitlabRouter = createTRPCRouter({
.input(apiFindGitlabBranches)
.query(async ({ input, ctx }) => {
const gitlabProvider = await findGitlabById(input.gitlabId || "");
- if (
- gitlabProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this Gitlab provider",
@@ -111,9 +107,10 @@ export const gitlabRouter = createTRPCRouter({
try {
const gitlabProvider = await findGitlabById(input.gitlabId || "");
if (
- gitlabProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
+ IS_CLOUD &&
+ gitlabProvider.gitProvider.adminId !== ctx.user.adminId
) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this Gitlab provider",
@@ -133,10 +130,8 @@ export const gitlabRouter = createTRPCRouter({
.input(apiUpdateGitlab)
.mutation(async ({ input, ctx }) => {
const gitlabProvider = await findGitlabById(input.gitlabId);
- if (
- gitlabProvider.gitProvider.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (IS_CLOUD && gitlabProvider.gitProvider.adminId !== ctx.user.adminId) {
+ //TODO: Remove this line when the cloud version is ready
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this Gitlab provider",
@@ -145,7 +140,7 @@ export const gitlabRouter = createTRPCRouter({
if (input.name) {
await updateGitProvider(input.gitProviderId, {
name: input.name,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
await updateGitlab(input.gitlabId, {
diff --git a/apps/dokploy/server/api/routers/mariadb.ts b/apps/dokploy/server/api/routers/mariadb.ts
index be0ffd39..09f4d675 100644
--- a/apps/dokploy/server/api/routers/mariadb.ts
+++ b/apps/dokploy/server/api/routers/mariadb.ts
@@ -9,7 +9,6 @@ import {
apiSaveExternalPortMariaDB,
apiUpdateMariaDB,
} from "@/server/db/schema";
-import { cancelJobs } from "@/server/utils/backup";
import {
IS_CLOUD,
addNewService,
@@ -17,9 +16,9 @@ import {
createMariadb,
createMount,
deployMariadb,
- findBackupsByDbId,
findMariadbById,
findProjectById,
+ findServerById,
removeMariadbById,
removeService,
startService,
@@ -36,13 +35,8 @@ export const mariadbRouter = createTRPCRouter({
.input(apiCreateMariaDB)
.mutation(async ({ input, ctx }) => {
try {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.projectId,
- ctx.session.activeOrganizationId,
- "create",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.projectId, "create");
}
if (IS_CLOUD && !input.serverId) {
@@ -53,19 +47,15 @@ export const mariadbRouter = createTRPCRouter({
}
const project = await findProjectById(input.projectId);
- if (project.organizationId !== ctx.session.activeOrganizationId) {
+ if (project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this project",
});
}
const newMariadb = await createMariadb(input);
- if (ctx.user.rol === "member") {
- await addNewService(
- ctx.user.id,
- newMariadb.mariadbId,
- project.organizationId,
- );
+ if (ctx.user.rol === "user") {
+ await addNewService(ctx.user.authId, newMariadb.mariadbId);
}
await createMount({
@@ -87,16 +77,11 @@ export const mariadbRouter = createTRPCRouter({
one: protectedProcedure
.input(apiFindOneMariaDB)
.query(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.mariadbId,
- ctx.session.activeOrganizationId,
- "access",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.mariadbId, "access");
}
const mariadb = await findMariadbById(input.mariadbId);
- if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mariadb.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this Mariadb",
@@ -109,7 +94,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiFindOneMariaDB)
.mutation(async ({ input, ctx }) => {
const service = await findMariadbById(input.mariadbId);
- if (service.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (service.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to start this Mariadb",
@@ -146,7 +131,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiSaveExternalPortMariaDB)
.mutation(async ({ input, ctx }) => {
const mongo = await findMariadbById(input.mariadbId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this external port",
@@ -162,7 +147,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiDeployMariaDB)
.mutation(async ({ input, ctx }) => {
const mariadb = await findMariadbById(input.mariadbId);
- if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mariadb.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Mariadb",
@@ -183,7 +168,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiDeployMariaDB)
.subscription(async ({ input, ctx }) => {
const mariadb = await findMariadbById(input.mariadbId);
- if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mariadb.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Mariadb",
@@ -200,7 +185,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiChangeMariaDBStatus)
.mutation(async ({ input, ctx }) => {
const mongo = await findMariadbById(input.mariadbId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to change this Mariadb status",
@@ -214,34 +199,27 @@ export const mariadbRouter = createTRPCRouter({
remove: protectedProcedure
.input(apiFindOneMariaDB)
.mutation(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.mariadbId,
- ctx.session.activeOrganizationId,
- "delete",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.mariadbId, "delete");
}
const mongo = await findMariadbById(input.mariadbId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this Mariadb",
});
}
- const backups = await findBackupsByDbId(input.mariadbId, "mariadb");
const cleanupOperations = [
async () => await removeService(mongo?.appName, mongo.serverId),
- async () => await cancelJobs(backups),
async () => await removeMariadbById(input.mariadbId),
];
for (const operation of cleanupOperations) {
try {
await operation();
- } catch (_) {}
+ } catch (error) {}
}
return mongo;
@@ -250,7 +228,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesMariaDB)
.mutation(async ({ input, ctx }) => {
const mariadb = await findMariadbById(input.mariadbId);
- if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mariadb.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this environment",
@@ -273,7 +251,7 @@ export const mariadbRouter = createTRPCRouter({
.input(apiResetMariadb)
.mutation(async ({ input, ctx }) => {
const mariadb = await findMariadbById(input.mariadbId);
- if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mariadb.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to reload this Mariadb",
@@ -303,7 +281,7 @@ export const mariadbRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const { mariadbId, ...rest } = input;
const mariadb = await findMariadbById(mariadbId);
- if (mariadb.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mariadb.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this Mariadb",
diff --git a/apps/dokploy/server/api/routers/mongo.ts b/apps/dokploy/server/api/routers/mongo.ts
index 1c3ba6bb..b114b8d8 100644
--- a/apps/dokploy/server/api/routers/mongo.ts
+++ b/apps/dokploy/server/api/routers/mongo.ts
@@ -9,7 +9,6 @@ import {
apiSaveExternalPortMongo,
apiUpdateMongo,
} from "@/server/db/schema";
-import { cancelJobs } from "@/server/utils/backup";
import {
IS_CLOUD,
addNewService,
@@ -17,7 +16,6 @@ import {
createMongo,
createMount,
deployMongo,
- findBackupsByDbId,
findMongoById,
findProjectById,
removeMongoById,
@@ -36,13 +34,8 @@ export const mongoRouter = createTRPCRouter({
.input(apiCreateMongo)
.mutation(async ({ input, ctx }) => {
try {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.projectId,
- ctx.session.activeOrganizationId,
- "create",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.projectId, "create");
}
if (IS_CLOUD && !input.serverId) {
@@ -53,19 +46,15 @@ export const mongoRouter = createTRPCRouter({
}
const project = await findProjectById(input.projectId);
- if (project.organizationId !== ctx.session.activeOrganizationId) {
+ if (project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this project",
});
}
const newMongo = await createMongo(input);
- if (ctx.user.rol === "member") {
- await addNewService(
- ctx.user.id,
- newMongo.mongoId,
- project.organizationId,
- );
+ if (ctx.user.rol === "user") {
+ await addNewService(ctx.user.authId, newMongo.mongoId);
}
await createMount({
@@ -91,17 +80,12 @@ export const mongoRouter = createTRPCRouter({
one: protectedProcedure
.input(apiFindOneMongo)
.query(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.mongoId,
- ctx.session.activeOrganizationId,
- "access",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.mongoId, "access");
}
const mongo = await findMongoById(input.mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this mongo",
@@ -115,7 +99,7 @@ export const mongoRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const service = await findMongoById(input.mongoId);
- if (service.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (service.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to start this mongo",
@@ -138,7 +122,7 @@ export const mongoRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to stop this mongo",
@@ -160,7 +144,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiSaveExternalPortMongo)
.mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this external port",
@@ -176,7 +160,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiDeployMongo)
.mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this mongo",
@@ -196,7 +180,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiDeployMongo)
.subscription(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this mongo",
@@ -213,7 +197,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiChangeMongoStatus)
.mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to change this mongo status",
@@ -228,7 +212,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiResetMongo)
.mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to reload this mongo",
@@ -256,35 +240,28 @@ export const mongoRouter = createTRPCRouter({
remove: protectedProcedure
.input(apiFindOneMongo)
.mutation(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.mongoId,
- ctx.session.activeOrganizationId,
- "delete",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.mongoId, "delete");
}
const mongo = await findMongoById(input.mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this mongo",
});
}
- const backups = await findBackupsByDbId(input.mongoId, "mongo");
const cleanupOperations = [
async () => await removeService(mongo?.appName, mongo.serverId),
- async () => await cancelJobs(backups),
async () => await removeMongoById(input.mongoId),
];
for (const operation of cleanupOperations) {
try {
await operation();
- } catch (_) {}
+ } catch (error) {}
}
return mongo;
@@ -293,7 +270,7 @@ export const mongoRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesMongo)
.mutation(async ({ input, ctx }) => {
const mongo = await findMongoById(input.mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this environment",
@@ -317,7 +294,7 @@ export const mongoRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const { mongoId, ...rest } = input;
const mongo = await findMongoById(mongoId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this mongo",
diff --git a/apps/dokploy/server/api/routers/mysql.ts b/apps/dokploy/server/api/routers/mysql.ts
index 594403f2..44d2537a 100644
--- a/apps/dokploy/server/api/routers/mysql.ts
+++ b/apps/dokploy/server/api/routers/mysql.ts
@@ -12,7 +12,6 @@ import {
import { TRPCError } from "@trpc/server";
-import { cancelJobs } from "@/server/utils/backup";
import {
IS_CLOUD,
addNewService,
@@ -20,7 +19,6 @@ import {
createMount,
createMysql,
deployMySql,
- findBackupsByDbId,
findMySqlById,
findProjectById,
removeMySqlById,
@@ -38,13 +36,8 @@ export const mysqlRouter = createTRPCRouter({
.input(apiCreateMySql)
.mutation(async ({ input, ctx }) => {
try {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.projectId,
- ctx.session.activeOrganizationId,
- "create",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.projectId, "create");
}
if (IS_CLOUD && !input.serverId) {
@@ -55,7 +48,7 @@ export const mysqlRouter = createTRPCRouter({
}
1;
const project = await findProjectById(input.projectId);
- if (project.organizationId !== ctx.session.activeOrganizationId) {
+ if (project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this project",
@@ -63,12 +56,8 @@ export const mysqlRouter = createTRPCRouter({
}
const newMysql = await createMysql(input);
- if (ctx.user.rol === "member") {
- await addNewService(
- ctx.user.id,
- newMysql.mysqlId,
- project.organizationId,
- );
+ if (ctx.user.rol === "user") {
+ await addNewService(ctx.user.authId, newMysql.mysqlId);
}
await createMount({
@@ -94,16 +83,11 @@ export const mysqlRouter = createTRPCRouter({
one: protectedProcedure
.input(apiFindOneMySql)
.query(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.mysqlId,
- ctx.session.activeOrganizationId,
- "access",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.mysqlId, "access");
}
const mysql = await findMySqlById(input.mysqlId);
- if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mysql.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this MySQL",
@@ -116,7 +100,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiFindOneMySql)
.mutation(async ({ input, ctx }) => {
const service = await findMySqlById(input.mysqlId);
- if (service.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (service.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to start this MySQL",
@@ -138,7 +122,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiFindOneMySql)
.mutation(async ({ input, ctx }) => {
const mongo = await findMySqlById(input.mysqlId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to stop this MySQL",
@@ -159,7 +143,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiSaveExternalPortMySql)
.mutation(async ({ input, ctx }) => {
const mongo = await findMySqlById(input.mysqlId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this external port",
@@ -175,7 +159,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiDeployMySql)
.mutation(async ({ input, ctx }) => {
const mysql = await findMySqlById(input.mysqlId);
- if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mysql.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this MySQL",
@@ -195,7 +179,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiDeployMySql)
.subscription(async ({ input, ctx }) => {
const mysql = await findMySqlById(input.mysqlId);
- if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mysql.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this MySQL",
@@ -212,7 +196,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiChangeMySqlStatus)
.mutation(async ({ input, ctx }) => {
const mongo = await findMySqlById(input.mysqlId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to change this MySQL status",
@@ -227,7 +211,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiResetMysql)
.mutation(async ({ input, ctx }) => {
const mysql = await findMySqlById(input.mysqlId);
- if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mysql.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to reload this MySQL",
@@ -254,33 +238,26 @@ export const mysqlRouter = createTRPCRouter({
remove: protectedProcedure
.input(apiFindOneMySql)
.mutation(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.mysqlId,
- ctx.session.activeOrganizationId,
- "delete",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.mysqlId, "delete");
}
const mongo = await findMySqlById(input.mysqlId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this MySQL",
});
}
- const backups = await findBackupsByDbId(input.mysqlId, "mysql");
const cleanupOperations = [
async () => await removeService(mongo?.appName, mongo.serverId),
- async () => await cancelJobs(backups),
async () => await removeMySqlById(input.mysqlId),
];
for (const operation of cleanupOperations) {
try {
await operation();
- } catch (_) {}
+ } catch (error) {}
}
return mongo;
@@ -289,7 +266,7 @@ export const mysqlRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesMySql)
.mutation(async ({ input, ctx }) => {
const mysql = await findMySqlById(input.mysqlId);
- if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mysql.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this environment",
@@ -313,7 +290,7 @@ export const mysqlRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const { mysqlId, ...rest } = input;
const mysql = await findMySqlById(mysqlId);
- if (mysql.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mysql.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this MySQL",
diff --git a/apps/dokploy/server/api/routers/notification.ts b/apps/dokploy/server/api/routers/notification.ts
index 23283d97..2eafc66d 100644
--- a/apps/dokploy/server/api/routers/notification.ts
+++ b/apps/dokploy/server/api/routers/notification.ts
@@ -23,8 +23,6 @@ import {
apiUpdateSlack,
apiUpdateTelegram,
notifications,
- server,
- users_temp,
} from "@/server/db/schema";
import {
IS_CLOUD,
@@ -38,7 +36,6 @@ import {
sendDiscordNotification,
sendEmailNotification,
sendGotifyNotification,
- sendServerThresholdNotifications,
sendSlackNotification,
sendTelegramNotification,
updateDiscordNotification,
@@ -48,18 +45,15 @@ import {
updateTelegramNotification,
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
-import { desc, eq, sql } from "drizzle-orm";
-import { z } from "zod";
+import { desc, eq } from "drizzle-orm";
+// TODO: Uncomment the validations when is cloud ready
export const notificationRouter = createTRPCRouter({
createSlack: adminProcedure
.input(apiCreateSlack)
.mutation(async ({ input, ctx }) => {
try {
- return await createSlackNotification(
- input,
- ctx.session.activeOrganizationId,
- );
+ return await createSlackNotification(input, ctx.user.adminId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
@@ -73,7 +67,8 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const notification = await findNotificationById(input.notificationId);
- if (notification.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && notification.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this notification",
@@ -81,7 +76,7 @@ export const notificationRouter = createTRPCRouter({
}
return await updateSlackNotification({
...input,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
} catch (error) {
throw error;
@@ -108,10 +103,7 @@ export const notificationRouter = createTRPCRouter({
.input(apiCreateTelegram)
.mutation(async ({ input, ctx }) => {
try {
- return await createTelegramNotification(
- input,
- ctx.session.activeOrganizationId,
- );
+ return await createTelegramNotification(input, ctx.user.adminId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
@@ -126,7 +118,8 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const notification = await findNotificationById(input.notificationId);
- if (notification.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && notification.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this notification",
@@ -134,7 +127,7 @@ export const notificationRouter = createTRPCRouter({
}
return await updateTelegramNotification({
...input,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
} catch (error) {
throw new TRPCError({
@@ -162,10 +155,7 @@ export const notificationRouter = createTRPCRouter({
.input(apiCreateDiscord)
.mutation(async ({ input, ctx }) => {
try {
- return await createDiscordNotification(
- input,
- ctx.session.activeOrganizationId,
- );
+ return await createDiscordNotification(input, ctx.user.adminId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
@@ -180,7 +170,8 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const notification = await findNotificationById(input.notificationId);
- if (notification.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && notification.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this notification",
@@ -188,7 +179,7 @@ export const notificationRouter = createTRPCRouter({
}
return await updateDiscordNotification({
...input,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
} catch (error) {
throw new TRPCError({
@@ -225,10 +216,7 @@ export const notificationRouter = createTRPCRouter({
.input(apiCreateEmail)
.mutation(async ({ input, ctx }) => {
try {
- return await createEmailNotification(
- input,
- ctx.session.activeOrganizationId,
- );
+ return await createEmailNotification(input, ctx.user.adminId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
@@ -242,7 +230,8 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const notification = await findNotificationById(input.notificationId);
- if (notification.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && notification.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this notification",
@@ -250,7 +239,7 @@ export const notificationRouter = createTRPCRouter({
}
return await updateEmailNotification({
...input,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
} catch (error) {
throw new TRPCError({
@@ -283,7 +272,8 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const notification = await findNotificationById(input.notificationId);
- if (notification.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && notification.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this notification",
@@ -291,13 +281,9 @@ export const notificationRouter = createTRPCRouter({
}
return await removeNotificationById(input.notificationId);
} catch (error) {
- const message =
- error instanceof Error
- ? error.message
- : "Error deleting this notification";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error deleting this notification",
});
}
}),
@@ -305,7 +291,8 @@ export const notificationRouter = createTRPCRouter({
.input(apiFindOneNotification)
.query(async ({ input, ctx }) => {
const notification = await findNotificationById(input.notificationId);
- if (notification.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && notification.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this notification",
@@ -323,81 +310,15 @@ export const notificationRouter = createTRPCRouter({
gotify: true,
},
orderBy: desc(notifications.createdAt),
- where: eq(notifications.organizationId, ctx.session.activeOrganizationId),
+ ...(IS_CLOUD && { where: eq(notifications.adminId, ctx.user.adminId) }),
+ // TODO: Remove this line when the cloud version is ready
});
}),
- receiveNotification: publicProcedure
- .input(
- z.object({
- ServerType: z.enum(["Dokploy", "Remote"]).default("Dokploy"),
- Type: z.enum(["Memory", "CPU"]),
- Value: z.number(),
- Threshold: z.number(),
- Message: z.string(),
- Timestamp: z.string(),
- Token: z.string(),
- }),
- )
- .mutation(async ({ input }) => {
- try {
- let organizationId = "";
- let ServerName = "";
- if (input.ServerType === "Dokploy") {
- const result = await db
- .select()
- .from(users_temp)
- .where(
- sql`${users_temp.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`,
- );
-
- if (!result?.[0]?.id) {
- throw new TRPCError({
- code: "BAD_REQUEST",
- message: "Token not found",
- });
- }
-
- organizationId = result?.[0]?.id;
- ServerName = "Dokploy";
- } else {
- const result = await db
- .select()
- .from(server)
- .where(
- sql`${server.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`,
- );
-
- if (!result?.[0]?.organizationId) {
- throw new TRPCError({
- code: "BAD_REQUEST",
- message: "Token not found",
- });
- }
-
- organizationId = result?.[0]?.organizationId;
- ServerName = "Remote";
- }
-
- await sendServerThresholdNotifications(organizationId, {
- ...input,
- ServerName,
- });
- } catch (error) {
- throw new TRPCError({
- code: "BAD_REQUEST",
- message: "Error sending the notification",
- cause: error,
- });
- }
- }),
createGotify: adminProcedure
.input(apiCreateGotify)
.mutation(async ({ input, ctx }) => {
try {
- return await createGotifyNotification(
- input,
- ctx.session.activeOrganizationId,
- );
+ return await createGotifyNotification(input, ctx.user.adminId);
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
@@ -411,10 +332,7 @@ export const notificationRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const notification = await findNotificationById(input.notificationId);
- if (
- IS_CLOUD &&
- notification.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (IS_CLOUD && notification.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this notification",
@@ -422,7 +340,7 @@ export const notificationRouter = createTRPCRouter({
}
return await updateGotifyNotification({
...input,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
} catch (error) {
throw error;
diff --git a/apps/dokploy/server/api/routers/organization.ts b/apps/dokploy/server/api/routers/organization.ts
deleted file mode 100644
index 6f7a9c67..00000000
--- a/apps/dokploy/server/api/routers/organization.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-import { db } from "@/server/db";
-import { invitation, member, organization } from "@/server/db/schema";
-import { IS_CLOUD } from "@dokploy/server/index";
-import { TRPCError } from "@trpc/server";
-import { and, desc, eq, exists } from "drizzle-orm";
-import { nanoid } from "nanoid";
-import { z } from "zod";
-import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc";
-export const organizationRouter = createTRPCRouter({
- create: protectedProcedure
- .input(
- z.object({
- name: z.string(),
- logo: z.string().optional(),
- }),
- )
- .mutation(async ({ ctx, input }) => {
- if (ctx.user.rol !== "owner" && !IS_CLOUD) {
- throw new TRPCError({
- code: "FORBIDDEN",
- message: "Only the organization owner can create an organization",
- });
- }
- const result = await db
- .insert(organization)
- .values({
- ...input,
- slug: nanoid(),
- createdAt: new Date(),
- ownerId: ctx.user.id,
- })
- .returning()
- .then((res) => res[0]);
-
- console.log("result", result);
-
- if (!result) {
- throw new TRPCError({
- code: "INTERNAL_SERVER_ERROR",
- message: "Failed to create organization",
- });
- }
-
- await db.insert(member).values({
- organizationId: result.id,
- role: "owner",
- createdAt: new Date(),
- userId: ctx.user.id,
- });
- return result;
- }),
- all: protectedProcedure.query(async ({ ctx }) => {
- const memberResult = await db.query.organization.findMany({
- where: (organization) =>
- exists(
- db
- .select()
- .from(member)
- .where(
- and(
- eq(member.organizationId, organization.id),
- eq(member.userId, ctx.user.id),
- ),
- ),
- ),
- });
- return memberResult;
- }),
- one: protectedProcedure
- .input(
- z.object({
- organizationId: z.string(),
- }),
- )
- .query(async ({ input }) => {
- return await db.query.organization.findFirst({
- where: eq(organization.id, input.organizationId),
- });
- }),
- update: protectedProcedure
- .input(
- z.object({
- organizationId: z.string(),
- name: z.string(),
- logo: z.string().optional(),
- }),
- )
- .mutation(async ({ ctx, input }) => {
- if (ctx.user.rol !== "owner" && !IS_CLOUD) {
- throw new TRPCError({
- code: "FORBIDDEN",
- message: "Only the organization owner can update it",
- });
- }
- const result = await db
- .update(organization)
- .set({
- name: input.name,
- logo: input.logo,
- })
- .where(eq(organization.id, input.organizationId))
- .returning();
- return result[0];
- }),
- delete: protectedProcedure
- .input(
- z.object({
- organizationId: z.string(),
- }),
- )
- .mutation(async ({ ctx, input }) => {
- if (ctx.user.rol !== "owner" && !IS_CLOUD) {
- throw new TRPCError({
- code: "FORBIDDEN",
- message: "Only the organization owner can delete it",
- });
- }
- const org = await db.query.organization.findFirst({
- where: eq(organization.id, input.organizationId),
- });
-
- if (!org) {
- throw new TRPCError({
- code: "NOT_FOUND",
- message: "Organization not found",
- });
- }
-
- if (org.ownerId !== ctx.user.id) {
- throw new TRPCError({
- code: "FORBIDDEN",
- message: "Only the organization owner can delete it",
- });
- }
-
- const result = await db
- .delete(organization)
- .where(eq(organization.id, input.organizationId));
-
- return result;
- }),
- allInvitations: adminProcedure.query(async ({ ctx }) => {
- return await db.query.invitation.findMany({
- where: eq(invitation.organizationId, ctx.session.activeOrganizationId),
- orderBy: [desc(invitation.status), desc(invitation.expiresAt)],
- });
- }),
-});
diff --git a/apps/dokploy/server/api/routers/port.ts b/apps/dokploy/server/api/routers/port.ts
index 923fea57..bfbc9863 100644
--- a/apps/dokploy/server/api/routers/port.ts
+++ b/apps/dokploy/server/api/routers/port.ts
@@ -44,11 +44,9 @@ export const portRouter = createTRPCRouter({
try {
return removePortById(input.portId);
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error input: Deleting port";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error input: Deleting port",
});
}
}),
@@ -58,11 +56,9 @@ export const portRouter = createTRPCRouter({
try {
return updatePortById(input.portId, input);
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error updating the port";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error updating the port",
});
}
}),
diff --git a/apps/dokploy/server/api/routers/postgres.ts b/apps/dokploy/server/api/routers/postgres.ts
index cf3221b4..7d178943 100644
--- a/apps/dokploy/server/api/routers/postgres.ts
+++ b/apps/dokploy/server/api/routers/postgres.ts
@@ -1,4 +1,9 @@
-import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
+import { EventEmitter } from "node:events";
+import {
+ createTRPCRouter,
+ protectedProcedure,
+ publicProcedure,
+} from "@/server/api/trpc";
import {
apiChangePostgresStatus,
apiCreatePostgres,
@@ -9,7 +14,6 @@ import {
apiSaveExternalPortPostgres,
apiUpdatePostgres,
} from "@/server/db/schema";
-import { cancelJobs } from "@/server/utils/backup";
import {
IS_CLOUD,
addNewService,
@@ -17,7 +21,6 @@ import {
createMount,
createPostgres,
deployPostgres,
- findBackupsByDbId,
findPostgresById,
findProjectById,
removePostgresById,
@@ -30,19 +33,17 @@ import {
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
import { observable } from "@trpc/server/observable";
+import { z } from "zod";
+
+const ee = new EventEmitter();
export const postgresRouter = createTRPCRouter({
create: protectedProcedure
.input(apiCreatePostgres)
.mutation(async ({ input, ctx }) => {
try {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.projectId,
- ctx.session.activeOrganizationId,
- "create",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.projectId, "create");
}
if (IS_CLOUD && !input.serverId) {
@@ -53,19 +54,15 @@ export const postgresRouter = createTRPCRouter({
}
const project = await findProjectById(input.projectId);
- if (project.organizationId !== ctx.session.activeOrganizationId) {
+ if (project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this project",
});
}
const newPostgres = await createPostgres(input);
- if (ctx.user.rol === "member") {
- await addNewService(
- ctx.user.id,
- newPostgres.postgresId,
- project.organizationId,
- );
+ if (ctx.user.rol === "user") {
+ await addNewService(ctx.user.authId, newPostgres.postgresId);
}
await createMount({
@@ -91,19 +88,12 @@ export const postgresRouter = createTRPCRouter({
one: protectedProcedure
.input(apiFindOnePostgres)
.query(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.postgresId,
- ctx.session.activeOrganizationId,
- "access",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.postgresId, "access");
}
const postgres = await findPostgresById(input.postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this Postgres",
@@ -117,7 +107,7 @@ export const postgresRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const service = await findPostgresById(input.postgresId);
- if (service.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (service.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to start this Postgres",
@@ -139,9 +129,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiFindOnePostgres)
.mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to stop this Postgres",
@@ -163,9 +151,7 @@ export const postgresRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this external port",
@@ -181,9 +167,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiDeployPostgres)
.mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Postgres",
@@ -204,9 +188,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiDeployPostgres)
.subscription(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Postgres",
@@ -223,9 +205,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiChangePostgresStatus)
.mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to change this Postgres status",
@@ -239,30 +219,20 @@ export const postgresRouter = createTRPCRouter({
remove: protectedProcedure
.input(apiFindOnePostgres)
.mutation(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.postgresId,
- ctx.session.activeOrganizationId,
- "delete",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.postgresId, "delete");
}
const postgres = await findPostgresById(input.postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this Postgres",
});
}
- const backups = await findBackupsByDbId(input.postgresId, "postgres");
-
const cleanupOperations = [
removeService(postgres.appName, postgres.serverId),
- cancelJobs(backups),
removePostgresById(input.postgresId),
];
@@ -274,9 +244,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesPostgres)
.mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this environment",
@@ -299,9 +267,7 @@ export const postgresRouter = createTRPCRouter({
.input(apiResetPostgres)
.mutation(async ({ input, ctx }) => {
const postgres = await findPostgresById(input.postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to reload this Postgres",
@@ -331,9 +297,7 @@ export const postgresRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const { postgresId, ...rest } = input;
const postgres = await findPostgresById(postgresId);
- if (
- postgres.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (postgres.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this Postgres",
diff --git a/apps/dokploy/server/api/routers/preview-deployment.ts b/apps/dokploy/server/api/routers/preview-deployment.ts
index f833e9f9..74b8461a 100644
--- a/apps/dokploy/server/api/routers/preview-deployment.ts
+++ b/apps/dokploy/server/api/routers/preview-deployment.ts
@@ -14,9 +14,7 @@ export const previewDeploymentRouter = createTRPCRouter({
.input(apiFindAllByApplication)
.query(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -30,10 +28,7 @@ export const previewDeploymentRouter = createTRPCRouter({
const previewDeployment = await findPreviewDeploymentById(
input.previewDeploymentId,
);
- if (
- previewDeployment.application.project.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (previewDeployment.application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this preview deployment",
@@ -48,10 +43,7 @@ export const previewDeploymentRouter = createTRPCRouter({
const previewDeployment = await findPreviewDeploymentById(
input.previewDeploymentId,
);
- if (
- previewDeployment.application.project.organizationId !==
- ctx.session.activeOrganizationId
- ) {
+ if (previewDeployment.application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this preview deployment",
diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts
index 438a3f07..9c2608cc 100644
--- a/apps/dokploy/server/api/routers/project.ts
+++ b/apps/dokploy/server/api/routers/project.ts
@@ -15,34 +15,32 @@ import {
redis,
} from "@/server/db/schema";
+import { TRPCError } from "@trpc/server";
+import { and, desc, eq, sql } from "drizzle-orm";
+import type { AnyPgColumn } from "drizzle-orm/pg-core";
+
import {
IS_CLOUD,
addNewProject,
checkProjectAccess,
createProject,
deleteProject,
- findMemberById,
+ findAdminById,
findProjectById,
- findUserById,
+ findUserByAuthId,
updateProjectById,
} from "@dokploy/server";
-import { TRPCError } from "@trpc/server";
-import { and, desc, eq, sql } from "drizzle-orm";
-import type { AnyPgColumn } from "drizzle-orm/pg-core";
+
export const projectRouter = createTRPCRouter({
create: protectedProcedure
.input(apiCreateProject)
.mutation(async ({ ctx, input }) => {
try {
- if (ctx.user.rol === "member") {
- await checkProjectAccess(
- ctx.user.id,
- "create",
- ctx.session.activeOrganizationId,
- );
+ if (ctx.user.rol === "user") {
+ await checkProjectAccess(ctx.user.authId, "create");
}
- const admin = await findUserById(ctx.user.ownerId);
+ const admin = await findAdminById(ctx.user.adminId);
if (admin.serversQuantity === 0 && IS_CLOUD) {
throw new TRPCError({
@@ -51,16 +49,9 @@ export const projectRouter = createTRPCRouter({
});
}
- const project = await createProject(
- input,
- ctx.session.activeOrganizationId,
- );
- if (ctx.user.rol === "member") {
- await addNewProject(
- ctx.user.id,
- project.projectId,
- ctx.session.activeOrganizationId,
- );
+ const project = await createProject(input, ctx.user.adminId);
+ if (ctx.user.rol === "user") {
+ await addNewProject(ctx.user.authId, project.projectId);
}
return project;
@@ -76,23 +67,15 @@ export const projectRouter = createTRPCRouter({
one: protectedProcedure
.input(apiFindOneProject)
.query(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- const { accessedServices } = await findMemberById(
- ctx.user.id,
- ctx.session.activeOrganizationId,
- );
+ if (ctx.user.rol === "user") {
+ const { accessedServices } = await findUserByAuthId(ctx.user.authId);
- await checkProjectAccess(
- ctx.user.id,
- "access",
- ctx.session.activeOrganizationId,
- input.projectId,
- );
+ await checkProjectAccess(ctx.user.authId, "access", input.projectId);
const project = await db.query.projects.findFirst({
where: and(
eq(projects.projectId, input.projectId),
- eq(projects.organizationId, ctx.session.activeOrganizationId),
+ eq(projects.adminId, ctx.user.adminId),
),
with: {
compose: {
@@ -132,7 +115,7 @@ export const projectRouter = createTRPCRouter({
}
const project = await findProjectById(input.projectId);
- if (project.organizationId !== ctx.session.activeOrganizationId) {
+ if (project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this project",
@@ -141,11 +124,9 @@ export const projectRouter = createTRPCRouter({
return project;
}),
all: protectedProcedure.query(async ({ ctx }) => {
- // console.log(ctx.user);
- if (ctx.user.rol === "member") {
- const { accessedProjects, accessedServices } = await findMemberById(
- ctx.user.id,
- ctx.session.activeOrganizationId,
+ if (ctx.user.rol === "user") {
+ const { accessedProjects, accessedServices } = await findUserByAuthId(
+ ctx.user.authId,
);
if (accessedProjects.length === 0) {
@@ -158,7 +139,7 @@ export const projectRouter = createTRPCRouter({
accessedProjects.map((projectId) => sql`${projectId}`),
sql`, `,
)})`,
- eq(projects.organizationId, ctx.session.activeOrganizationId),
+ eq(projects.adminId, ctx.user.adminId),
),
with: {
applications: {
@@ -212,26 +193,19 @@ export const projectRouter = createTRPCRouter({
},
},
},
- where: eq(projects.organizationId, ctx.session.activeOrganizationId),
+ where: eq(projects.adminId, ctx.user.adminId),
orderBy: desc(projects.createdAt),
});
}),
-
remove: protectedProcedure
.input(apiRemoveProject)
.mutation(async ({ input, ctx }) => {
try {
- if (ctx.user.rol === "member") {
- await checkProjectAccess(
- ctx.user.id,
- "delete",
- ctx.session.activeOrganizationId,
- );
+ if (ctx.user.rol === "user") {
+ await checkProjectAccess(ctx.user.authId, "delete");
}
const currentProject = await findProjectById(input.projectId);
- if (
- currentProject.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (currentProject.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this project",
@@ -249,9 +223,7 @@ export const projectRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const currentProject = await findProjectById(input.projectId);
- if (
- currentProject.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (currentProject.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this project",
diff --git a/apps/dokploy/server/api/routers/redirects.ts b/apps/dokploy/server/api/routers/redirects.ts
index 2d520cc4..bcd7962a 100644
--- a/apps/dokploy/server/api/routers/redirects.ts
+++ b/apps/dokploy/server/api/routers/redirects.ts
@@ -18,9 +18,7 @@ export const redirectsRouter = createTRPCRouter({
.input(apiCreateRedirect)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -33,9 +31,7 @@ export const redirectsRouter = createTRPCRouter({
.query(async ({ input, ctx }) => {
const redirect = await findRedirectById(input.redirectId);
const application = await findApplicationById(redirect.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -48,9 +44,7 @@ export const redirectsRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const redirect = await findRedirectById(input.redirectId);
const application = await findApplicationById(redirect.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -63,9 +57,7 @@ export const redirectsRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const redirect = await findRedirectById(input.redirectId);
const application = await findApplicationById(redirect.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
diff --git a/apps/dokploy/server/api/routers/redis.ts b/apps/dokploy/server/api/routers/redis.ts
index a80660bf..5883e50b 100644
--- a/apps/dokploy/server/api/routers/redis.ts
+++ b/apps/dokploy/server/api/routers/redis.ts
@@ -36,13 +36,8 @@ export const redisRouter = createTRPCRouter({
.input(apiCreateRedis)
.mutation(async ({ input, ctx }) => {
try {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.projectId,
- ctx.session.activeOrganizationId,
- "create",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.projectId, "create");
}
if (IS_CLOUD && !input.serverId) {
@@ -53,19 +48,15 @@ export const redisRouter = createTRPCRouter({
}
const project = await findProjectById(input.projectId);
- if (project.organizationId !== ctx.session.activeOrganizationId) {
+ if (project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this project",
});
}
const newRedis = await createRedis(input);
- if (ctx.user.rol === "member") {
- await addNewService(
- ctx.user.id,
- newRedis.redisId,
- project.organizationId,
- );
+ if (ctx.user.rol === "user") {
+ await addNewService(ctx.user.authId, newRedis.redisId);
}
await createMount({
@@ -84,17 +75,12 @@ export const redisRouter = createTRPCRouter({
one: protectedProcedure
.input(apiFindOneRedis)
.query(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.redisId,
- ctx.session.activeOrganizationId,
- "access",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.redisId, "access");
}
const redis = await findRedisById(input.redisId);
- if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (redis.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this Redis",
@@ -107,7 +93,7 @@ export const redisRouter = createTRPCRouter({
.input(apiFindOneRedis)
.mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId);
- if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (redis.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to start this Redis",
@@ -129,7 +115,7 @@ export const redisRouter = createTRPCRouter({
.input(apiResetRedis)
.mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId);
- if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (redis.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to reload this Redis",
@@ -159,7 +145,7 @@ export const redisRouter = createTRPCRouter({
.input(apiFindOneRedis)
.mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId);
- if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (redis.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to stop this Redis",
@@ -180,7 +166,7 @@ export const redisRouter = createTRPCRouter({
.input(apiSaveExternalPortRedis)
.mutation(async ({ input, ctx }) => {
const mongo = await findRedisById(input.redisId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this external port",
@@ -196,7 +182,7 @@ export const redisRouter = createTRPCRouter({
.input(apiDeployRedis)
.mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId);
- if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (redis.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Redis",
@@ -216,7 +202,7 @@ export const redisRouter = createTRPCRouter({
.input(apiDeployRedis)
.subscription(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId);
- if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (redis.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to deploy this Redis",
@@ -232,7 +218,7 @@ export const redisRouter = createTRPCRouter({
.input(apiChangeRedisStatus)
.mutation(async ({ input, ctx }) => {
const mongo = await findRedisById(input.redisId);
- if (mongo.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (mongo.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to change this Redis status",
@@ -246,23 +232,19 @@ export const redisRouter = createTRPCRouter({
remove: protectedProcedure
.input(apiFindOneRedis)
.mutation(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- await checkServiceAccess(
- ctx.user.id,
- input.redisId,
- ctx.session.activeOrganizationId,
- "delete",
- );
+ if (ctx.user.rol === "user") {
+ await checkServiceAccess(ctx.user.authId, input.redisId, "delete");
}
const redis = await findRedisById(input.redisId);
- if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (redis.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this Redis",
});
}
+
const cleanupOperations = [
async () => await removeService(redis?.appName, redis.serverId),
async () => await removeRedisById(input.redisId),
@@ -271,7 +253,7 @@ export const redisRouter = createTRPCRouter({
for (const operation of cleanupOperations) {
try {
await operation();
- } catch (_) {}
+ } catch (error) {}
}
return redis;
@@ -280,7 +262,7 @@ export const redisRouter = createTRPCRouter({
.input(apiSaveEnvironmentVariablesRedis)
.mutation(async ({ input, ctx }) => {
const redis = await findRedisById(input.redisId);
- if (redis.project.organizationId !== ctx.session.activeOrganizationId) {
+ if (redis.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to save this environment",
diff --git a/apps/dokploy/server/api/routers/registry.ts b/apps/dokploy/server/api/routers/registry.ts
index a9a6be89..f66ed4ae 100644
--- a/apps/dokploy/server/api/routers/registry.ts
+++ b/apps/dokploy/server/api/routers/registry.ts
@@ -1,35 +1,34 @@
-import { db } from "@/server/db";
import {
apiCreateRegistry,
apiFindOneRegistry,
apiRemoveRegistry,
apiTestRegistry,
apiUpdateRegistry,
- registry,
} from "@/server/db/schema";
import {
IS_CLOUD,
createRegistry,
execAsync,
execAsyncRemote,
+ findAllRegistryByAdminId,
findRegistryById,
removeRegistry,
updateRegistry,
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
-import { eq } from "drizzle-orm";
import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc";
+
export const registryRouter = createTRPCRouter({
create: adminProcedure
.input(apiCreateRegistry)
.mutation(async ({ ctx, input }) => {
- return await createRegistry(input, ctx.session.activeOrganizationId);
+ return await createRegistry(input, ctx.user.adminId);
}),
remove: adminProcedure
.input(apiRemoveRegistry)
.mutation(async ({ ctx, input }) => {
const registry = await findRegistryById(input.registryId);
- if (registry.organizationId !== ctx.session.activeOrganizationId) {
+ if (registry.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to delete this registry",
@@ -42,7 +41,7 @@ export const registryRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const { registryId, ...rest } = input;
const registry = await findRegistryById(registryId);
- if (registry.organizationId !== ctx.session.activeOrganizationId) {
+ if (registry.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to update this registry",
@@ -62,16 +61,13 @@ export const registryRouter = createTRPCRouter({
return true;
}),
all: protectedProcedure.query(async ({ ctx }) => {
- const registryResponse = await db.query.registry.findMany({
- where: eq(registry.organizationId, ctx.session.activeOrganizationId),
- });
- return registryResponse;
+ return await findAllRegistryByAdminId(ctx.user.adminId);
}),
one: adminProcedure
.input(apiFindOneRegistry)
.query(async ({ input, ctx }) => {
const registry = await findRegistryById(input.registryId);
- if (registry.organizationId !== ctx.session.activeOrganizationId) {
+ if (registry.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this registry",
diff --git a/apps/dokploy/server/api/routers/security.ts b/apps/dokploy/server/api/routers/security.ts
index b8e70bbb..5318a293 100644
--- a/apps/dokploy/server/api/routers/security.ts
+++ b/apps/dokploy/server/api/routers/security.ts
@@ -18,9 +18,7 @@ export const securityRouter = createTRPCRouter({
.input(apiCreateSecurity)
.mutation(async ({ input, ctx }) => {
const application = await findApplicationById(input.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -33,9 +31,7 @@ export const securityRouter = createTRPCRouter({
.query(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId);
const application = await findApplicationById(security.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -48,9 +44,7 @@ export const securityRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId);
const application = await findApplicationById(security.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
@@ -63,9 +57,7 @@ export const securityRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
const security = await findSecurityById(input.securityId);
const application = await findApplicationById(security.applicationId);
- if (
- application.project.organizationId !== ctx.session.activeOrganizationId
- ) {
+ if (application.project.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this application",
diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts
index 1a9ebc0a..382bb98a 100644
--- a/apps/dokploy/server/api/routers/server.ts
+++ b/apps/dokploy/server/api/routers/server.ts
@@ -6,13 +6,11 @@ import {
apiFindOneServer,
apiRemoveServer,
apiUpdateServer,
- apiUpdateServerMonitoring,
applications,
compose,
mariadb,
mongo,
mysql,
- organization,
postgres,
redis,
server,
@@ -22,40 +20,35 @@ import {
createServer,
defaultCommand,
deleteServer,
+ findAdminById,
findServerById,
- findServersByUserId,
- findUserById,
+ findServersByAdminId,
getPublicIpWithFallback,
haveActiveServices,
removeDeploymentsByServerId,
serverAudit,
serverSetup,
serverValidate,
- setupMonitoring,
updateServerById,
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
import { observable } from "@trpc/server/observable";
import { and, desc, eq, getTableColumns, isNotNull, sql } from "drizzle-orm";
-import { z } from "zod";
export const serverRouter = createTRPCRouter({
create: protectedProcedure
.input(apiCreateServer)
.mutation(async ({ ctx, input }) => {
try {
- const user = await findUserById(ctx.user.ownerId);
- const servers = await findServersByUserId(user.id);
- if (IS_CLOUD && servers.length >= user.serversQuantity) {
+ const admin = await findAdminById(ctx.user.adminId);
+ const servers = await findServersByAdminId(admin.adminId);
+ if (IS_CLOUD && servers.length >= admin.serversQuantity) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "You cannot create more servers",
});
}
- const project = await createServer(
- input,
- ctx.session.activeOrganizationId,
- );
+ const project = await createServer(input, ctx.user.adminId);
return project;
} catch (error) {
throw new TRPCError({
@@ -70,7 +63,7 @@ export const serverRouter = createTRPCRouter({
.input(apiFindOneServer)
.query(async ({ input, ctx }) => {
const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session.activeOrganizationId) {
+ if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this server",
@@ -81,7 +74,7 @@ export const serverRouter = createTRPCRouter({
}),
getDefaultCommand: protectedProcedure
.input(apiFindOneServer)
- .query(async () => {
+ .query(async ({ input, ctx }) => {
return defaultCommand();
}),
all: protectedProcedure.query(async ({ ctx }) => {
@@ -98,37 +91,22 @@ export const serverRouter = createTRPCRouter({
.leftJoin(mongo, eq(mongo.serverId, server.serverId))
.leftJoin(mysql, eq(mysql.serverId, server.serverId))
.leftJoin(postgres, eq(postgres.serverId, server.serverId))
- .where(eq(server.organizationId, ctx.session.activeOrganizationId))
+ .where(eq(server.adminId, ctx.user.adminId))
.orderBy(desc(server.createdAt))
.groupBy(server.serverId);
return result;
}),
- count: protectedProcedure.query(async ({ ctx }) => {
- const organizations = await db.query.organization.findMany({
- where: eq(organization.ownerId, ctx.user.id),
- with: {
- servers: true,
- },
- });
-
- const servers = organizations.flatMap((org) => org.servers);
-
- return servers.length ?? 0;
- }),
withSSHKey: protectedProcedure.query(async ({ ctx }) => {
const result = await db.query.server.findMany({
orderBy: desc(server.createdAt),
where: IS_CLOUD
? and(
isNotNull(server.sshKeyId),
- eq(server.organizationId, ctx.session.activeOrganizationId),
+ eq(server.adminId, ctx.user.adminId),
eq(server.serverStatus, "active"),
)
- : and(
- isNotNull(server.sshKeyId),
- eq(server.organizationId, ctx.session.activeOrganizationId),
- ),
+ : and(isNotNull(server.sshKeyId), eq(server.adminId, ctx.user.adminId)),
});
return result;
}),
@@ -137,7 +115,7 @@ export const serverRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session.activeOrganizationId) {
+ if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to setup this server",
@@ -162,7 +140,7 @@ export const serverRouter = createTRPCRouter({
.subscription(async ({ input, ctx }) => {
try {
const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session.activeOrganizationId) {
+ if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to setup this server",
@@ -182,7 +160,7 @@ export const serverRouter = createTRPCRouter({
.query(async ({ input, ctx }) => {
try {
const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session.activeOrganizationId) {
+ if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to validate this server",
@@ -224,7 +202,7 @@ export const serverRouter = createTRPCRouter({
.query(async ({ input, ctx }) => {
try {
const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session.activeOrganizationId) {
+ if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to validate this server",
@@ -269,54 +247,12 @@ export const serverRouter = createTRPCRouter({
});
}
}),
- setupMonitoring: protectedProcedure
- .input(apiUpdateServerMonitoring)
- .mutation(async ({ input, ctx }) => {
- try {
- const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session.activeOrganizationId) {
- throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "You are not authorized to setup this server",
- });
- }
-
- await updateServerById(input.serverId, {
- metricsConfig: {
- server: {
- type: "Remote",
- refreshRate: input.metricsConfig.server.refreshRate,
- retentionDays: input.metricsConfig.server.retentionDays,
- port: input.metricsConfig.server.port,
- token: input.metricsConfig.server.token,
- urlCallback: input.metricsConfig.server.urlCallback,
- cronJob: input.metricsConfig.server.cronJob,
- thresholds: {
- cpu: input.metricsConfig.server.thresholds.cpu,
- memory: input.metricsConfig.server.thresholds.memory,
- },
- },
- containers: {
- refreshRate: input.metricsConfig.containers.refreshRate,
- services: {
- include: input.metricsConfig.containers.services.include || [],
- exclude: input.metricsConfig.containers.services.exclude || [],
- },
- },
- },
- });
- const currentServer = await setupMonitoring(input.serverId);
- return currentServer;
- } catch (error) {
- throw error;
- }
- }),
remove: protectedProcedure
.input(apiRemoveServer)
.mutation(async ({ input, ctx }) => {
try {
const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session.activeOrganizationId) {
+ if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to delete this server",
@@ -335,9 +271,12 @@ export const serverRouter = createTRPCRouter({
await deleteServer(input.serverId);
if (IS_CLOUD) {
- const admin = await findUserById(ctx.user.ownerId);
+ const admin = await findAdminById(ctx.user.adminId);
- await updateServersBasedOnQuantity(admin.id, admin.serversQuantity);
+ await updateServersBasedOnQuantity(
+ admin.adminId,
+ admin.serversQuantity,
+ );
}
return currentServer;
@@ -350,7 +289,7 @@ export const serverRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session.activeOrganizationId) {
+ if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to update this server",
@@ -372,69 +311,11 @@ export const serverRouter = createTRPCRouter({
throw error;
}
}),
- publicIp: protectedProcedure.query(async () => {
+ publicIp: protectedProcedure.query(async ({ ctx }) => {
if (IS_CLOUD) {
return "";
}
const ip = await getPublicIpWithFallback();
return ip;
}),
- getServerMetrics: protectedProcedure
- .input(
- z.object({
- url: z.string(),
- token: z.string(),
- dataPoints: z.string(),
- }),
- )
- .query(async ({ input }) => {
- try {
- const url = new URL(input.url);
- url.searchParams.append("limit", input.dataPoints);
- const response = await fetch(url.toString(), {
- headers: {
- Authorization: `Bearer ${input.token}`,
- },
- });
- if (!response.ok) {
- throw new Error(
- `Error ${response.status}: ${response.statusText}. Ensure the container is running and this service is included in the monitoring configuration.`,
- );
- }
-
- const data = await response.json();
- if (!Array.isArray(data) || data.length === 0) {
- throw new Error(
- [
- "No monitoring data available. This could be because:",
- "",
- "1. You don't have setup the monitoring service, you can do in web server section.",
- "2. If you already have setup the monitoring service, wait a few minutes and refresh the page.",
- ].join("\n"),
- );
- }
- return data as {
- cpu: string;
- cpuModel: string;
- cpuCores: number;
- cpuPhysicalCores: number;
- cpuSpeed: number;
- os: string;
- distro: string;
- kernel: string;
- arch: string;
- memUsed: string;
- memUsedGB: string;
- memTotal: string;
- uptime: number;
- diskUsed: string;
- totalDisk: string;
- networkIn: string;
- networkOut: string;
- timestamp: string;
- }[];
- } catch (error) {
- throw error;
- }
- }),
});
diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts
index fc1255fc..449a2233 100644
--- a/apps/dokploy/server/api/routers/settings.ts
+++ b/apps/dokploy/server/api/routers/settings.ts
@@ -22,8 +22,9 @@ import {
cleanUpUnusedVolumes,
execAsync,
execAsyncRemote,
+ findAdmin,
+ findAdminById,
findServerById,
- findUserById,
getDokployImage,
getDokployImageTag,
getUpdateData,
@@ -46,10 +47,10 @@ import {
startServiceRemote,
stopService,
stopServiceRemote,
+ updateAdmin,
updateLetsEncryptEmail,
updateServerById,
updateServerTraefik,
- updateUser,
writeConfig,
writeMainConfig,
writeTraefikConfigInPath,
@@ -163,7 +164,7 @@ export const settingsRouter = createTRPCRouter({
if (IS_CLOUD) {
return true;
}
- await updateUser(ctx.user.id, {
+ await updateAdmin(ctx.user.authId, {
sshPrivateKey: input.sshPrivateKey,
});
@@ -175,7 +176,7 @@ export const settingsRouter = createTRPCRouter({
if (IS_CLOUD) {
return true;
}
- const user = await updateUser(ctx.user.id, {
+ const admin = await updateAdmin(ctx.user.authId, {
host: input.host,
...(input.letsEncryptEmail && {
letsEncryptEmail: input.letsEncryptEmail,
@@ -183,25 +184,25 @@ export const settingsRouter = createTRPCRouter({
certificateType: input.certificateType,
});
- if (!user) {
+ if (!admin) {
throw new TRPCError({
code: "NOT_FOUND",
- message: "User not found",
+ message: "Admin not found",
});
}
- updateServerTraefik(user, input.host);
+ updateServerTraefik(admin, input.host);
if (input.letsEncryptEmail) {
updateLetsEncryptEmail(input.letsEncryptEmail);
}
- return user;
+ return admin;
}),
cleanSSHPrivateKey: adminProcedure.mutation(async ({ ctx }) => {
if (IS_CLOUD) {
return true;
}
- await updateUser(ctx.user.id, {
+ await updateAdmin(ctx.user.authId, {
sshPrivateKey: null,
});
return true;
@@ -216,7 +217,7 @@ export const settingsRouter = createTRPCRouter({
const server = await findServerById(input.serverId);
- if (server.organizationId !== ctx.session?.activeOrganizationId) {
+ if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to access this server",
@@ -245,7 +246,7 @@ export const settingsRouter = createTRPCRouter({
await cleanUpUnusedImages(server.serverId);
await cleanUpDockerBuilder(server.serverId);
await cleanUpSystemPrune(server.serverId);
- await sendDockerCleanupNotifications(server.organizationId);
+ await sendDockerCleanupNotifications(server.adminId);
});
}
} else {
@@ -261,11 +262,19 @@ export const settingsRouter = createTRPCRouter({
}
}
} else if (!IS_CLOUD) {
- const userUpdated = await updateUser(ctx.user.id, {
+ const admin = await findAdminById(ctx.user.adminId);
+
+ if (admin.adminId !== ctx.user.adminId) {
+ throw new TRPCError({
+ code: "UNAUTHORIZED",
+ message: "You are not authorized to access this admin",
+ });
+ }
+ const adminUpdated = await updateAdmin(ctx.user.authId, {
enableDockerCleanup: input.enableDockerCleanup,
});
- if (userUpdated?.enableDockerCleanup) {
+ if (adminUpdated?.enableDockerCleanup) {
scheduleJob("docker-cleanup", "0 0 * * *", async () => {
console.log(
`Docker Cleanup ${new Date().toLocaleString()}] Running...`,
@@ -273,9 +282,7 @@ export const settingsRouter = createTRPCRouter({
await cleanUpUnusedImages();
await cleanUpDockerBuilder();
await cleanUpSystemPrune();
- await sendDockerCleanupNotifications(
- ctx.session.activeOrganizationId,
- );
+ await sendDockerCleanupNotifications(admin.adminId);
});
} else {
const currentJob = scheduledJobs["docker-cleanup"];
@@ -338,7 +345,7 @@ export const settingsRouter = createTRPCRouter({
writeConfig("middlewares", input.traefikConfig);
return true;
}),
- getUpdateData: protectedProcedure.mutation(async () => {
+ getUpdateData: adminProcedure.mutation(async () => {
if (IS_CLOUD) {
return DEFAULT_UPDATE_DATA;
}
@@ -366,21 +373,18 @@ export const settingsRouter = createTRPCRouter({
return true;
}),
- getDokployVersion: protectedProcedure.query(() => {
+ getDokployVersion: adminProcedure.query(() => {
return packageInfo.version;
}),
- getReleaseTag: protectedProcedure.query(() => {
+ getReleaseTag: adminProcedure.query(() => {
return getDokployImageTag();
}),
readDirectories: protectedProcedure
.input(apiServerSchema)
.query(async ({ ctx, input }) => {
try {
- if (ctx.user.rol === "member") {
- const canAccess = await canAccessToTraefikFiles(
- ctx.user.id,
- ctx.session.activeOrganizationId,
- );
+ if (ctx.user.rol === "user") {
+ const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
if (!canAccess) {
throw new TRPCError({ code: "UNAUTHORIZED" });
@@ -397,11 +401,8 @@ export const settingsRouter = createTRPCRouter({
updateTraefikFile: protectedProcedure
.input(apiModifyTraefikConfig)
.mutation(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- const canAccess = await canAccessToTraefikFiles(
- ctx.user.id,
- ctx.session.activeOrganizationId,
- );
+ if (ctx.user.rol === "user") {
+ const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
if (!canAccess) {
throw new TRPCError({ code: "UNAUTHORIZED" });
@@ -418,11 +419,8 @@ export const settingsRouter = createTRPCRouter({
readTraefikFile: protectedProcedure
.input(apiReadTraefikConfig)
.query(async ({ input, ctx }) => {
- if (ctx.user.rol === "member") {
- const canAccess = await canAccessToTraefikFiles(
- ctx.user.id,
- ctx.session.activeOrganizationId,
- );
+ if (ctx.user.rol === "user") {
+ const canAccess = await canAccessToTraefikFiles(ctx.user.authId);
if (!canAccess) {
throw new TRPCError({ code: "UNAUTHORIZED" });
@@ -430,12 +428,12 @@ export const settingsRouter = createTRPCRouter({
}
return readConfigInPath(input.path, input.serverId);
}),
- getIp: protectedProcedure.query(async ({ ctx }) => {
+ getIp: protectedProcedure.query(async () => {
if (IS_CLOUD) {
return true;
}
- const user = await findUserById(ctx.user.ownerId);
- return user.serverIp;
+ const admin = await findAdmin();
+ return admin.serverIp;
}),
getOpenApiDocument: protectedProcedure.query(
@@ -482,28 +480,10 @@ export const settingsRouter = createTRPCRouter({
openApiDocument.info = {
title: "Dokploy API",
description: "Endpoints for dokploy",
+ // TODO: get version from package.json
version: "1.0.0",
};
- // Add security schemes configuration
- openApiDocument.components = {
- ...openApiDocument.components,
- securitySchemes: {
- apiKey: {
- type: "apiKey",
- in: "header",
- name: "x-api-key",
- description: "API key authentication",
- },
- },
- };
-
- // Apply security globally to all endpoints
- openApiDocument.security = [
- {
- apiKey: [],
- },
- ];
return openApiDocument;
},
),
@@ -675,7 +655,7 @@ export const settingsRouter = createTRPCRouter({
return true;
}),
- isCloud: publicProcedure.query(async () => {
+ isCloud: protectedProcedure.query(async () => {
return IS_CLOUD;
}),
health: publicProcedure.query(async () => {
@@ -735,12 +715,7 @@ export const settingsRouter = createTRPCRouter({
try {
return await checkGPUStatus(input.serverId || "");
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Failed to check GPU status";
- throw new TRPCError({
- code: "BAD_REQUEST",
- message,
- });
+ throw new Error("Failed to check GPU status");
}
}),
updateTraefikPorts: adminProcedure
diff --git a/apps/dokploy/server/api/routers/ssh-key.ts b/apps/dokploy/server/api/routers/ssh-key.ts
index 4663af8f..fe2f24f9 100644
--- a/apps/dokploy/server/api/routers/ssh-key.ts
+++ b/apps/dokploy/server/api/routers/ssh-key.ts
@@ -9,6 +9,7 @@ import {
sshKeys,
} from "@/server/db/schema";
import {
+ IS_CLOUD,
createSshKey,
findSSHKeyById,
generateSSHKey,
@@ -25,7 +26,7 @@ export const sshRouter = createTRPCRouter({
try {
await createSshKey({
...input,
- organizationId: ctx.session.activeOrganizationId,
+ adminId: ctx.user.adminId,
});
} catch (error) {
throw new TRPCError({
@@ -40,7 +41,8 @@ export const sshRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const sshKey = await findSSHKeyById(input.sshKeyId);
- if (sshKey.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && sshKey.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to delete this SSH key",
@@ -57,7 +59,8 @@ export const sshRouter = createTRPCRouter({
.query(async ({ input, ctx }) => {
const sshKey = await findSSHKeyById(input.sshKeyId);
- if (sshKey.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && sshKey.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to access this SSH key",
@@ -67,9 +70,10 @@ export const sshRouter = createTRPCRouter({
}),
all: protectedProcedure.query(async ({ ctx }) => {
return await db.query.sshKeys.findMany({
- where: eq(sshKeys.organizationId, ctx.session.activeOrganizationId),
+ ...(IS_CLOUD && { where: eq(sshKeys.adminId, ctx.user.adminId) }),
orderBy: desc(sshKeys.createdAt),
});
+ // TODO: Remove this line when the cloud version is ready
}),
generate: protectedProcedure
.input(apiGenerateSSHKey)
@@ -81,7 +85,8 @@ export const sshRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => {
try {
const sshKey = await findSSHKeyById(input.sshKeyId);
- if (sshKey.organizationId !== ctx.session.activeOrganizationId) {
+ if (IS_CLOUD && sshKey.adminId !== ctx.user.adminId) {
+ // TODO: Remove isCloud in the next versions of dokploy
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not allowed to update this SSH key",
diff --git a/apps/dokploy/server/api/routers/stripe.ts b/apps/dokploy/server/api/routers/stripe.ts
index a226eeac..7a8a537c 100644
--- a/apps/dokploy/server/api/routers/stripe.ts
+++ b/apps/dokploy/server/api/routers/stripe.ts
@@ -1,9 +1,9 @@
import { WEBSITE_URL, getStripeItems } from "@/server/utils/stripe";
import {
IS_CLOUD,
- findServersByUserId,
- findUserById,
- updateUser,
+ findAdminById,
+ findServersByAdminId,
+ updateAdmin,
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
import Stripe from "stripe";
@@ -12,8 +12,8 @@ import { adminProcedure, createTRPCRouter } from "../trpc";
export const stripeRouter = createTRPCRouter({
getProducts: adminProcedure.query(async ({ ctx }) => {
- const user = await findUserById(ctx.user.ownerId);
- const stripeCustomerId = user.stripeCustomerId;
+ const admin = await findAdminById(ctx.user.adminId);
+ const stripeCustomerId = admin.stripeCustomerId;
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2024-09-30.acacia",
@@ -56,15 +56,15 @@ export const stripeRouter = createTRPCRouter({
});
const items = getStripeItems(input.serverQuantity, input.isAnnual);
- const user = await findUserById(ctx.user.id);
+ const admin = await findAdminById(ctx.user.adminId);
- let stripeCustomerId = user.stripeCustomerId;
+ let stripeCustomerId = admin.stripeCustomerId;
if (stripeCustomerId) {
const customer = await stripe.customers.retrieve(stripeCustomerId);
if (customer.deleted) {
- await updateUser(user.id, {
+ await updateAdmin(admin.authId, {
stripeCustomerId: null,
});
stripeCustomerId = null;
@@ -78,7 +78,7 @@ export const stripeRouter = createTRPCRouter({
customer: stripeCustomerId,
}),
metadata: {
- adminId: user.id,
+ adminId: admin.adminId,
},
allow_promotion_codes: true,
success_url: `${WEBSITE_URL}/dashboard/settings/servers?success=true`,
@@ -87,43 +87,45 @@ export const stripeRouter = createTRPCRouter({
return { sessionId: session.id };
}),
- createCustomerPortalSession: adminProcedure.mutation(async ({ ctx }) => {
- const user = await findUserById(ctx.user.id);
+ createCustomerPortalSession: adminProcedure.mutation(
+ async ({ ctx, input }) => {
+ const admin = await findAdminById(ctx.user.adminId);
- if (!user.stripeCustomerId) {
- throw new TRPCError({
- code: "BAD_REQUEST",
- message: "Stripe Customer ID not found",
- });
- }
- const stripeCustomerId = user.stripeCustomerId;
+ if (!admin.stripeCustomerId) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Stripe Customer ID not found",
+ });
+ }
+ const stripeCustomerId = admin.stripeCustomerId;
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
- apiVersion: "2024-09-30.acacia",
- });
-
- try {
- const session = await stripe.billingPortal.sessions.create({
- customer: stripeCustomerId,
- return_url: `${WEBSITE_URL}/dashboard/settings/billing`,
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
+ apiVersion: "2024-09-30.acacia",
});
- return { url: session.url };
- } catch (_) {
- return {
- url: "",
- };
- }
- }),
+ try {
+ const session = await stripe.billingPortal.sessions.create({
+ customer: stripeCustomerId,
+ return_url: `${WEBSITE_URL}/dashboard/settings/billing`,
+ });
+
+ return { url: session.url };
+ } catch (error) {
+ return {
+ url: "",
+ };
+ }
+ },
+ ),
canCreateMoreServers: adminProcedure.query(async ({ ctx }) => {
- const user = await findUserById(ctx.user.ownerId);
- const servers = await findServersByUserId(user.id);
+ const admin = await findAdminById(ctx.user.adminId);
+ const servers = await findServersByAdminId(admin.adminId);
if (!IS_CLOUD) {
return true;
}
- return servers.length < user.serversQuantity;
+ return servers.length < admin.serversQuantity;
}),
});
diff --git a/apps/dokploy/server/api/routers/user.ts b/apps/dokploy/server/api/routers/user.ts
index 0b740ab7..91db9826 100644
--- a/apps/dokploy/server/api/routers/user.ts
+++ b/apps/dokploy/server/api/routers/user.ts
@@ -1,330 +1,34 @@
-import {
- IS_CLOUD,
- findOrganizationById,
- findUserById,
- getUserByToken,
- removeUserById,
- updateUser,
- createApiKey,
-} from "@dokploy/server";
-import { db } from "@dokploy/server/db";
-import {
- account,
- apiAssignPermissions,
- apiFindOneToken,
- apiUpdateUser,
- invitation,
- member,
- apikey,
-} from "@dokploy/server/db/schema";
-import * as bcrypt from "bcrypt";
+import { apiFindOneUser, apiFindOneUserByAuth } from "@/server/db/schema";
+import { findUserByAuthId, findUserById, findUsers } from "@dokploy/server";
import { TRPCError } from "@trpc/server";
-import { and, asc, eq, gt } from "drizzle-orm";
-import { z } from "zod";
-import {
- adminProcedure,
- createTRPCRouter,
- protectedProcedure,
- publicProcedure,
-} from "../trpc";
-
-const apiCreateApiKey = z.object({
- name: z.string().min(1),
- prefix: z.string().optional(),
- expiresIn: z.number().optional(),
- metadata: z.object({
- organizationId: z.string(),
- }),
- // Rate limiting
- rateLimitEnabled: z.boolean().optional(),
- rateLimitTimeWindow: z.number().optional(),
- rateLimitMax: z.number().optional(),
- // Request limiting
- remaining: z.number().optional(),
- refillAmount: z.number().optional(),
- refillInterval: z.number().optional(),
-});
+import { adminProcedure, createTRPCRouter, protectedProcedure } from "../trpc";
export const userRouter = createTRPCRouter({
all: adminProcedure.query(async ({ ctx }) => {
- return await db.query.member.findMany({
- where: eq(member.organizationId, ctx.session.activeOrganizationId),
- with: {
- user: true,
- },
- orderBy: [asc(member.createdAt)],
- });
+ return await findUsers(ctx.user.adminId);
}),
- one: protectedProcedure
- .input(
- z.object({
- userId: z.string(),
- }),
- )
+ byAuthId: protectedProcedure
+ .input(apiFindOneUserByAuth)
.query(async ({ input, ctx }) => {
- const memberResult = await db.query.member.findFirst({
- where: and(
- eq(member.userId, input.userId),
- eq(member.organizationId, ctx.session?.activeOrganizationId || ""),
- ),
- with: {
- user: true,
- },
- });
-
- return memberResult;
- }),
- get: protectedProcedure.query(async ({ ctx }) => {
- const memberResult = await db.query.member.findFirst({
- where: and(
- eq(member.userId, ctx.user.id),
- eq(member.organizationId, ctx.session?.activeOrganizationId || ""),
- ),
- with: {
- user: {
- with: {
- apiKeys: true,
- },
- },
- },
- });
-
- return memberResult;
- }),
- getServerMetrics: protectedProcedure.query(async ({ ctx }) => {
- const memberResult = await db.query.member.findFirst({
- where: and(
- eq(member.userId, ctx.user.id),
- eq(member.organizationId, ctx.session?.activeOrganizationId || ""),
- ),
- with: {
- user: true,
- },
- });
-
- return memberResult?.user;
- }),
- update: protectedProcedure
- .input(apiUpdateUser)
- .mutation(async ({ input, ctx }) => {
- if (input.password || input.currentPassword) {
- const currentAuth = await db.query.account.findFirst({
- where: eq(account.userId, ctx.user.id),
+ const user = await findUserByAuthId(input.authId);
+ if (user.adminId !== ctx.user.adminId) {
+ throw new TRPCError({
+ code: "UNAUTHORIZED",
+ message: "You are not allowed to access this user",
});
- const correctPassword = bcrypt.compareSync(
- input.currentPassword || "",
- currentAuth?.password || "",
- );
-
- if (!correctPassword) {
- throw new TRPCError({
- code: "BAD_REQUEST",
- message: "Current password is incorrect",
- });
- }
-
- if (!input.password) {
- throw new TRPCError({
- code: "BAD_REQUEST",
- message: "New password is required",
- });
- }
- await db
- .update(account)
- .set({
- password: bcrypt.hashSync(input.password, 10),
- })
- .where(eq(account.userId, ctx.user.id));
}
- return await updateUser(ctx.user.id, input);
+ return user;
}),
- getUserByToken: publicProcedure
- .input(apiFindOneToken)
- .query(async ({ input }) => {
- return await getUserByToken(input.token);
- }),
- getMetricsToken: protectedProcedure.query(async ({ ctx }) => {
- const user = await findUserById(ctx.user.ownerId);
- return {
- serverIp: user.serverIp,
- enabledFeatures: user.enablePaidFeatures,
- metricsConfig: user?.metricsConfig,
- };
- }),
- remove: protectedProcedure
- .input(
- z.object({
- userId: z.string(),
- }),
- )
- .mutation(async ({ input }) => {
- if (IS_CLOUD) {
- return true;
- }
- return await removeUserById(input.userId);
- }),
- assignPermissions: adminProcedure
- .input(apiAssignPermissions)
- .mutation(async ({ input, ctx }) => {
- try {
- const organization = await findOrganizationById(
- ctx.session?.activeOrganizationId || "",
- );
-
- if (organization?.ownerId !== ctx.user.ownerId) {
- throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "You are not allowed to assign permissions",
- });
- }
-
- const { id, ...rest } = input;
-
- await db
- .update(member)
- .set({
- ...rest,
- })
- .where(
- and(
- eq(member.userId, input.id),
- eq(
- member.organizationId,
- ctx.session?.activeOrganizationId || "",
- ),
- ),
- );
- } catch (error) {
- throw error;
- }
- }),
- getInvitations: protectedProcedure.query(async ({ ctx }) => {
- return await db.query.invitation.findMany({
- where: and(
- eq(invitation.email, ctx.user.email),
- gt(invitation.expiresAt, new Date()),
- eq(invitation.status, "pending"),
- ),
- with: {
- organization: true,
- },
- });
- }),
-
- getContainerMetrics: protectedProcedure
- .input(
- z.object({
- url: z.string(),
- token: z.string(),
- appName: z.string(),
- dataPoints: z.string(),
- }),
- )
- .query(async ({ input }) => {
- try {
- if (!input.appName) {
- throw new Error(
- [
- "No Application Selected:",
- "",
- "Make Sure to select an application to monitor.",
- ].join("\n"),
- );
- }
- const url = new URL(`${input.url}/metrics/containers`);
- url.searchParams.append("limit", input.dataPoints);
- url.searchParams.append("appName", input.appName);
- const response = await fetch(url.toString(), {
- headers: {
- Authorization: `Bearer ${input.token}`,
- },
+ byUserId: protectedProcedure
+ .input(apiFindOneUser)
+ .query(async ({ input, ctx }) => {
+ const user = await findUserById(input.userId);
+ if (user.adminId !== ctx.user.adminId) {
+ throw new TRPCError({
+ code: "UNAUTHORIZED",
+ message: "You are not allowed to access this user",
});
- if (!response.ok) {
- throw new Error(
- `Error ${response.status}: ${response.statusText}. Please verify that the application "${input.appName}" is running and this service is included in the monitoring configuration.`,
- );
- }
-
- const data = await response.json();
- if (!Array.isArray(data) || data.length === 0) {
- throw new Error(
- [
- `No monitoring data available for "${input.appName}". This could be because:`,
- "",
- "1. The container was recently started - wait a few minutes for data to be collected",
- "2. The container is not running - verify its status",
- "3. The service is not included in your monitoring configuration",
- ].join("\n"),
- );
- }
- return data as {
- containerId: string;
- containerName: string;
- containerImage: string;
- containerLabels: string;
- containerCommand: string;
- containerCreated: string;
- }[];
- } catch (error) {
- throw error;
}
- }),
-
- generateToken: protectedProcedure.mutation(async () => {
- return "token";
- }),
-
- deleteApiKey: protectedProcedure
- .input(
- z.object({
- apiKeyId: z.string(),
- }),
- )
- .mutation(async ({ input, ctx }) => {
- try {
- const apiKeyToDelete = await db.query.apikey.findFirst({
- where: eq(apikey.id, input.apiKeyId),
- });
-
- if (!apiKeyToDelete) {
- throw new TRPCError({
- code: "NOT_FOUND",
- message: "API key not found",
- });
- }
-
- if (apiKeyToDelete.userId !== ctx.user.id) {
- throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "You are not authorized to delete this API key",
- });
- }
-
- await db.delete(apikey).where(eq(apikey.id, input.apiKeyId));
- return true;
- } catch (error) {
- throw error;
- }
- }),
-
- createApiKey: protectedProcedure
- .input(apiCreateApiKey)
- .mutation(async ({ input, ctx }) => {
- const apiKey = await createApiKey(ctx.user.id, input);
- return apiKey;
- }),
-
- checkUserOrganizations: protectedProcedure
- .input(
- z.object({
- userId: z.string(),
- }),
- )
- .query(async ({ input }) => {
- const organizations = await db.query.member.findMany({
- where: eq(member.userId, input.userId),
- });
-
- return organizations.length;
+ return user;
}),
});
diff --git a/apps/dokploy/server/api/trpc.ts b/apps/dokploy/server/api/trpc.ts
index 4c88eb22..db4f7adf 100644
--- a/apps/dokploy/server/api/trpc.ts
+++ b/apps/dokploy/server/api/trpc.ts
@@ -9,7 +9,7 @@
// import { getServerAuthSession } from "@/server/auth";
import { db } from "@/server/db";
-import { validateRequest } from "@dokploy/server/lib/auth";
+import { validateBearerToken, validateRequest } from "@dokploy/server";
import type { OpenApiMeta } from "@dokploy/trpc-openapi";
import { TRPCError, initTRPC } from "@trpc/server";
import type { CreateNextContextOptions } from "@trpc/server/adapters/next";
@@ -18,7 +18,7 @@ import {
experimental_isMultipartFormDataRequest,
experimental_parseMultipartFormData,
} from "@trpc/server/adapters/node-http/content-type/form-data";
-import type { Session, User } from "better-auth";
+import type { Session, User } from "lucia";
import superjson from "superjson";
import { ZodError } from "zod";
/**
@@ -30,8 +30,8 @@ import { ZodError } from "zod";
*/
interface CreateContextOptions {
- user: (User & { rol: "member" | "admin" | "owner"; ownerId: string }) | null;
- session: (Session & { activeOrganizationId: string }) | null;
+ user: (User & { authId: string; adminId: string }) | null;
+ session: Session | null;
req: CreateNextContextOptions["req"];
res: CreateNextContextOptions["res"];
}
@@ -65,29 +65,30 @@ const createInnerTRPCContext = (opts: CreateContextOptions) => {
export const createTRPCContext = async (opts: CreateNextContextOptions) => {
const { req, res } = opts;
- // Get from the request
- const { session, user } = await validateRequest(req);
+ let { session, user } = await validateBearerToken(req);
+
+ if (!session) {
+ const cookieResult = await validateRequest(req, res);
+ session = cookieResult.session;
+ user = cookieResult.user;
+ }
return createInnerTRPCContext({
req,
res,
- // @ts-ignore
- session: session
- ? {
- ...session,
- activeOrganizationId: session.activeOrganizationId || "",
- }
- : null,
- // @ts-ignore
- user: user
- ? {
- ...user,
- email: user.email,
- rol: user.role as "owner" | "member" | "admin",
- id: user.id,
- ownerId: user.ownerId,
- }
- : null,
+ session: session,
+ ...((user && {
+ user: {
+ authId: user.id,
+ email: user.email,
+ rol: user.rol,
+ id: user.id,
+ secret: user.secret,
+ adminId: user.adminId,
+ },
+ }) || {
+ user: null,
+ }),
});
};
@@ -180,7 +181,7 @@ export const uploadProcedure = async (opts: any) => {
};
export const cliProcedure = t.procedure.use(({ ctx, next }) => {
- if (!ctx.session || !ctx.user || ctx.user.rol !== "owner") {
+ if (!ctx.session || !ctx.user || ctx.user.rol !== "admin") {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
@@ -194,7 +195,7 @@ export const cliProcedure = t.procedure.use(({ ctx, next }) => {
});
export const adminProcedure = t.procedure.use(({ ctx, next }) => {
- if (!ctx.session || !ctx.user || ctx.user.rol !== "owner") {
+ if (!ctx.session || !ctx.user || ctx.user.rol !== "admin") {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
diff --git a/apps/dokploy/server/db/seed.ts b/apps/dokploy/server/db/seed.ts
index 5b3eb6c6..b7935079 100644
--- a/apps/dokploy/server/db/seed.ts
+++ b/apps/dokploy/server/db/seed.ts
@@ -1,10 +1,16 @@
+import bc from "bcrypt";
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
+import { users } from "./schema";
const connectionString = process.env.DATABASE_URL!;
const pg = postgres(connectionString, { max: 1 });
-const _db = drizzle(pg);
+const db = drizzle(pg);
+
+function password(txt: string) {
+ return bc.hashSync(txt, 10);
+}
async function seed() {
console.log("> Seed:", process.env.DATABASE_PATH, "\n");
diff --git a/apps/dokploy/server/utils/backup.ts b/apps/dokploy/server/utils/backup.ts
index 4fc9db93..a178063f 100644
--- a/apps/dokploy/server/utils/backup.ts
+++ b/apps/dokploy/server/utils/backup.ts
@@ -1,9 +1,3 @@
-import {
- type BackupScheduleList,
- IS_CLOUD,
- removeScheduleBackup,
-} from "@dokploy/server/index";
-
type QueueJob =
| {
type: "backup";
@@ -65,19 +59,3 @@ export const updateJob = async (job: QueueJob) => {
throw error;
}
};
-
-export const cancelJobs = async (backups: BackupScheduleList) => {
- for (const backup of backups) {
- if (backup.enabled) {
- if (IS_CLOUD) {
- await removeJob({
- cronSchedule: backup.schedule,
- backupId: backup.backupId,
- type: "backup",
- });
- } else {
- removeScheduleBackup(backup.backupId);
- }
- }
- }
-};
diff --git a/apps/dokploy/server/utils/docker.ts b/apps/dokploy/server/utils/docker.ts
index 3314eb62..92008678 100644
--- a/apps/dokploy/server/utils/docker.ts
+++ b/apps/dokploy/server/utils/docker.ts
@@ -6,7 +6,7 @@ export const isWSL = async () => {
const { stdout } = await execAsync("uname -r");
const isWSL = stdout.includes("microsoft");
return isWSL;
- } catch (_error) {
+ } catch (error) {
return false;
}
};
diff --git a/apps/dokploy/server/wss/docker-container-logs.ts b/apps/dokploy/server/wss/docker-container-logs.ts
index 8d08ebd4..092f3973 100644
--- a/apps/dokploy/server/wss/docker-container-logs.ts
+++ b/apps/dokploy/server/wss/docker-container-logs.ts
@@ -1,5 +1,5 @@
import type http from "node:http";
-import { findServerById, validateRequest } from "@dokploy/server";
+import { findServerById, validateWebSocketRequest } from "@dokploy/server";
import { spawn } from "node-pty";
import { Client } from "ssh2";
import { WebSocketServer } from "ws";
@@ -35,7 +35,7 @@ export const setupDockerContainerLogsWebSocketServer = (
const since = url.searchParams.get("since");
const serverId = url.searchParams.get("serverId");
const runType = url.searchParams.get("runType");
- const { user, session } = await validateRequest(req);
+ const { user, session } = await validateWebSocketRequest(req);
if (!containerId) {
ws.close(4000, "containerId no provided");
diff --git a/apps/dokploy/server/wss/docker-container-terminal.ts b/apps/dokploy/server/wss/docker-container-terminal.ts
index 2f25edb1..8981ccbc 100644
--- a/apps/dokploy/server/wss/docker-container-terminal.ts
+++ b/apps/dokploy/server/wss/docker-container-terminal.ts
@@ -1,5 +1,5 @@
import type http from "node:http";
-import { findServerById, validateRequest } from "@dokploy/server";
+import { findServerById, validateWebSocketRequest } from "@dokploy/server";
import { spawn } from "node-pty";
import { Client } from "ssh2";
import { WebSocketServer } from "ws";
@@ -32,7 +32,7 @@ export const setupDockerContainerTerminalWebSocketServer = (
const containerId = url.searchParams.get("containerId");
const activeWay = url.searchParams.get("activeWay");
const serverId = url.searchParams.get("serverId");
- const { user, session } = await validateRequest(req);
+ const { user, session } = await validateWebSocketRequest(req);
if (!containerId) {
ws.close(4000, "containerId no provided");
@@ -50,8 +50,8 @@ export const setupDockerContainerTerminalWebSocketServer = (
throw new Error("No SSH key available for this server");
const conn = new Client();
- let _stdout = "";
- let _stderr = "";
+ let stdout = "";
+ let stderr = "";
conn
.once("ready", () => {
conn.exec(
@@ -61,16 +61,16 @@ export const setupDockerContainerTerminalWebSocketServer = (
if (err) throw err;
stream
- .on("close", (code: number, _signal: string) => {
+ .on("close", (code: number, signal: string) => {
ws.send(`\nContainer closed with code: ${code}\n`);
conn.end();
})
.on("data", (data: string) => {
- _stdout += data.toString();
+ stdout += data.toString();
ws.send(data.toString());
})
.stderr.on("data", (data) => {
- _stderr += data.toString();
+ stderr += data.toString();
ws.send(data.toString());
console.error("Error: ", data.toString());
});
diff --git a/apps/dokploy/server/wss/docker-stats.ts b/apps/dokploy/server/wss/docker-stats.ts
index 99e993dc..89d94687 100644
--- a/apps/dokploy/server/wss/docker-stats.ts
+++ b/apps/dokploy/server/wss/docker-stats.ts
@@ -1,10 +1,9 @@
import type http from "node:http";
import {
docker,
- execAsync,
getLastAdvancedStatsFile,
recordAdvancedStats,
- validateRequest,
+ validateWebSocketRequest,
} from "@dokploy/server";
import { WebSocketServer } from "ws";
@@ -36,7 +35,7 @@ export const setupDockerStatsMonitoringSocketServer = (
| "application"
| "stack"
| "docker-compose";
- const { user, session } = await validateRequest(req);
+ const { user, session } = await validateWebSocketRequest(req);
if (!appName) {
ws.close(4000, "appName no provided");
@@ -71,16 +70,12 @@ export const setupDockerStatsMonitoringSocketServer = (
ws.close(4000, "Container not running");
return;
}
- const { stdout, stderr } = await execAsync(
- `docker stats ${container.Id} --no-stream --format \'{"BlockIO":"{{.BlockIO}}","CPUPerc":"{{.CPUPerc}}","Container":"{{.Container}}","ID":"{{.ID}}","MemPerc":"{{.MemPerc}}","MemUsage":"{{.MemUsage}}","Name":"{{.Name}}","NetIO":"{{.NetIO}}"}\'`,
- );
- if (stderr) {
- console.error("Docker stats error:", stderr);
- return;
- }
- const stat = JSON.parse(stdout);
- await recordAdvancedStats(stat, appName);
+ const stats = await docker.getContainer(container.Id).stats({
+ stream: false,
+ });
+
+ await recordAdvancedStats(stats, appName);
const data = await getLastAdvancedStatsFile(appName);
ws.send(
diff --git a/apps/dokploy/server/wss/drawer-logs.ts b/apps/dokploy/server/wss/drawer-logs.ts
index 404dfeee..c1dec315 100644
--- a/apps/dokploy/server/wss/drawer-logs.ts
+++ b/apps/dokploy/server/wss/drawer-logs.ts
@@ -1,5 +1,4 @@
import type http from "node:http";
-import { validateRequest } from "@dokploy/server/index";
import { applyWSSHandler } from "@trpc/server/adapters/ws";
import { WebSocketServer } from "ws";
import { appRouter } from "../api/root";
@@ -32,12 +31,6 @@ export const setupDrawerLogsWebSocketServer = (
});
wssTerm.on("connection", async (ws, req) => {
- const _url = new URL(req.url || "", `http://${req.headers.host}`);
- const { user, session } = await validateRequest(req);
-
- if (!user || !session) {
- ws.close();
- return;
- }
+ const url = new URL(req.url || "", `http://${req.headers.host}`);
});
};
diff --git a/apps/dokploy/server/wss/listen-deployment.ts b/apps/dokploy/server/wss/listen-deployment.ts
index 4a25c6f0..df77ceb4 100644
--- a/apps/dokploy/server/wss/listen-deployment.ts
+++ b/apps/dokploy/server/wss/listen-deployment.ts
@@ -1,6 +1,6 @@
import { spawn } from "node:child_process";
import type http from "node:http";
-import { findServerById, validateRequest } from "@dokploy/server";
+import { findServerById, validateWebSocketRequest } from "@dokploy/server";
import { Client } from "ssh2";
import { WebSocketServer } from "ws";
@@ -29,7 +29,7 @@ export const setupDeploymentLogsWebSocketServer = (
const url = new URL(req.url || "", `http://${req.headers.host}`);
const logPath = url.searchParams.get("logPath");
const serverId = url.searchParams.get("serverId");
- const { user, session } = await validateRequest(req);
+ const { user, session } = await validateWebSocketRequest(req);
if (!logPath) {
console.log("logPath no provided");
@@ -103,7 +103,7 @@ export const setupDeploymentLogsWebSocketServer = (
ws.close();
});
}
- } catch (_error) {
+ } catch (error) {
// @ts-ignore
// const errorMessage = error?.message as unknown as string;
// ws.send(errorMessage);
diff --git a/apps/dokploy/server/wss/terminal.ts b/apps/dokploy/server/wss/terminal.ts
index 094c5e15..5fa1accc 100644
--- a/apps/dokploy/server/wss/terminal.ts
+++ b/apps/dokploy/server/wss/terminal.ts
@@ -1,5 +1,9 @@
import type http from "node:http";
-import { IS_CLOUD, findServerById, validateRequest } from "@dokploy/server";
+import {
+ IS_CLOUD,
+ findServerById,
+ validateWebSocketRequest,
+} from "@dokploy/server";
import { publicIpv4, publicIpv6 } from "public-ip";
import { Client, type ConnectConfig } from "ssh2";
import { WebSocketServer } from "ws";
@@ -67,7 +71,7 @@ export const setupTerminalWebSocketServer = (
wssTerm.on("connection", async (ws, req) => {
const url = new URL(req.url || "", `http://${req.headers.host}`);
const serverId = url.searchParams.get("serverId");
- const { user, session } = await validateRequest(req);
+ const { user, session } = await validateWebSocketRequest(req);
if (!user || !session || !serverId) {
ws.close();
return;
@@ -144,8 +148,8 @@ export const setupTerminalWebSocketServer = (
}
const conn = new Client();
- let _stdout = "";
- let _stderr = "";
+ let stdout = "";
+ let stderr = "";
ws.send("Connecting...\n");
@@ -158,16 +162,16 @@ export const setupTerminalWebSocketServer = (
if (err) throw err;
stream
- .on("close", (code: number, _signal: string) => {
+ .on("close", (code: number, signal: string) => {
ws.send(`\nContainer closed with code: ${code}\n`);
conn.end();
})
.on("data", (data: string) => {
- _stdout += data.toString();
+ stdout += data.toString();
ws.send(data.toString());
})
.stderr.on("data", (data) => {
- _stderr += data.toString();
+ stderr += data.toString();
ws.send(data.toString());
console.error("Error: ", data.toString());
});
diff --git a/apps/dokploy/styles/globals.css b/apps/dokploy/styles/globals.css
index 74a1d276..7b7977b9 100644
--- a/apps/dokploy/styles/globals.css
+++ b/apps/dokploy/styles/globals.css
@@ -4,7 +4,6 @@
@layer base {
:root {
- --terminal-paste: rgba(0, 0, 0, 0.2);
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
@@ -52,7 +51,6 @@
}
.dark {
- --terminal-paste: rgba(255, 255, 255, 0.2);
--background: 0 0% 0%;
--foreground: 0 0% 98%;
@@ -237,8 +235,3 @@
background-color: hsl(var(--muted-foreground) / 0.5);
}
}
-
-.xterm-bg-257.xterm-fg-257 {
- background-color: var(--terminal-paste) !important;
- color: currentColor !important;
-}
diff --git a/apps/dokploy/templates/activepieces/docker-compose.yml b/apps/dokploy/templates/activepieces/docker-compose.yml
index a5511e7f..e990379b 100644
--- a/apps/dokploy/templates/activepieces/docker-compose.yml
+++ b/apps/dokploy/templates/activepieces/docker-compose.yml
@@ -4,7 +4,8 @@ services:
activepieces:
image: activepieces/activepieces:0.35.0
restart: unless-stopped
-
+ networks:
+ - dokploy-network
depends_on:
postgres:
condition: service_healthy
@@ -34,7 +35,8 @@ services:
postgres:
image: postgres:14
restart: unless-stopped
-
+ networks:
+ - dokploy-network
environment:
POSTGRES_DB: activepieces
POSTGRES_PASSWORD: ${AP_POSTGRES_PASSWORD}
@@ -50,7 +52,8 @@ services:
redis:
image: redis:7
restart: unless-stopped
-
+ networks:
+ - dokploy-network
volumes:
- redis_data:/data
healthcheck:
diff --git a/apps/dokploy/templates/alist/docker-compose.yml b/apps/dokploy/templates/alist/docker-compose.yml
deleted file mode 100644
index 9ff67c94..00000000
--- a/apps/dokploy/templates/alist/docker-compose.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-version: '3.3'
-services:
- alist:
- image: xhofe/alist:v3.41.0
- volumes:
- - alist-data:/opt/alist/data
- environment:
- - PUID=0
- - PGID=0
- - UMASK=022
- restart: unless-stopped
-
-volumes:
- alist-data:
\ No newline at end of file
diff --git a/apps/dokploy/templates/alist/index.ts b/apps/dokploy/templates/alist/index.ts
deleted file mode 100644
index 2a27f570..00000000
--- a/apps/dokploy/templates/alist/index.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 5244,
- serviceName: "alist",
- },
- ];
-
- return {
- domains,
- };
-}
diff --git a/apps/dokploy/templates/answer/docker-compose.yml b/apps/dokploy/templates/answer/docker-compose.yml
deleted file mode 100644
index 2b9fc344..00000000
--- a/apps/dokploy/templates/answer/docker-compose.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-services:
- answer:
- image: apache/answer:1.4.1
- ports:
- - '80'
- restart: on-failure
- volumes:
- - answer-data:/data
- depends_on:
- db:
- condition: service_healthy
- db:
- image: postgres:16
- restart: always
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
- interval: 5s
- timeout: 5s
- retries: 5
-
- volumes:
- - db-data:/var/lib/postgresql/data
- environment:
- POSTGRES_DB: answer
- POSTGRES_USER: postgres
- POSTGRES_PASSWORD: postgres
-
-volumes:
- answer-data:
- db-data:
diff --git a/apps/dokploy/templates/answer/index.ts b/apps/dokploy/templates/answer/index.ts
deleted file mode 100644
index 36d48cb3..00000000
--- a/apps/dokploy/templates/answer/index.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateHash,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainServiceHash = generateHash(schema.projectName);
- const mainDomain = generateRandomDomain(schema);
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 9080,
- serviceName: "answer",
- },
- ];
-
- const envs = [
- `ANSWER_HOST=http://${mainDomain}`,
- `SERVICE_HASH=${mainServiceHash}`,
- ];
-
- const mounts: Template["mounts"] = [];
-
- return {
- envs,
- mounts,
- domains,
- };
-}
diff --git a/apps/dokploy/templates/appsmith/index.ts b/apps/dokploy/templates/appsmith/index.ts
index 73279e91..ff744a24 100644
--- a/apps/dokploy/templates/appsmith/index.ts
+++ b/apps/dokploy/templates/appsmith/index.ts
@@ -7,7 +7,7 @@ import {
} from "../utils";
export function generate(schema: Schema): Template {
- const _mainServiceHash = generateHash(schema.projectName);
+ const mainServiceHash = generateHash(schema.projectName);
const domains: DomainSchema[] = [
{
diff --git a/apps/dokploy/templates/appwrite/docker-compose.yml b/apps/dokploy/templates/appwrite/docker-compose.yml
deleted file mode 100644
index 163cb3d0..00000000
--- a/apps/dokploy/templates/appwrite/docker-compose.yml
+++ /dev/null
@@ -1,887 +0,0 @@
-version: "3.8"
-
-x-logging: &x-logging
- logging:
- driver: "json-file"
- options:
- max-file: "5"
- max-size: "10m"
-
-services:
- appwrite:
- image: appwrite/appwrite:1.6.0
- container_name: appwrite
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- labels:
- - traefik.enable=true
- - traefik.constraint-label-stack=appwrite
- volumes:
- - appwrite-uploads:/storage/uploads:rw
- - appwrite-cache:/storage/cache:rw
- - appwrite-config:/storage/config:rw
- - appwrite-certificates:/storage/certificates:rw
- - appwrite-functions:/storage/functions:rw
- depends_on:
- - mariadb
- - redis
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_LOCALE
- - _APP_CONSOLE_WHITELIST_ROOT
- - _APP_CONSOLE_WHITELIST_EMAILS
- - _APP_CONSOLE_SESSION_ALERTS
- - _APP_CONSOLE_WHITELIST_IPS
- - _APP_CONSOLE_HOSTNAMES
- - _APP_SYSTEM_EMAIL_NAME
- - _APP_SYSTEM_EMAIL_ADDRESS
- - _APP_EMAIL_SECURITY
- - _APP_SYSTEM_RESPONSE_FORMAT
- - _APP_OPTIONS_ABUSE
- - _APP_OPTIONS_ROUTER_PROTECTION
- - _APP_OPTIONS_FORCE_HTTPS
- - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS
- - _APP_OPENSSL_KEY_V1
- - _APP_DOMAIN
- - _APP_DOMAIN_TARGET
- - _APP_DOMAIN_FUNCTIONS
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_SMTP_HOST
- - _APP_SMTP_PORT
- - _APP_SMTP_SECURE
- - _APP_SMTP_USERNAME
- - _APP_SMTP_PASSWORD
- - _APP_USAGE_STATS
- - _APP_STORAGE_LIMIT
- - _APP_STORAGE_PREVIEW_LIMIT
- - _APP_STORAGE_ANTIVIRUS
- - _APP_STORAGE_ANTIVIRUS_HOST
- - _APP_STORAGE_ANTIVIRUS_PORT
- - _APP_STORAGE_DEVICE
- - _APP_STORAGE_S3_ACCESS_KEY
- - _APP_STORAGE_S3_SECRET
- - _APP_STORAGE_S3_REGION
- - _APP_STORAGE_S3_BUCKET
- - _APP_STORAGE_DO_SPACES_ACCESS_KEY
- - _APP_STORAGE_DO_SPACES_SECRET
- - _APP_STORAGE_DO_SPACES_REGION
- - _APP_STORAGE_DO_SPACES_BUCKET
- - _APP_STORAGE_BACKBLAZE_ACCESS_KEY
- - _APP_STORAGE_BACKBLAZE_SECRET
- - _APP_STORAGE_BACKBLAZE_REGION
- - _APP_STORAGE_BACKBLAZE_BUCKET
- - _APP_STORAGE_LINODE_ACCESS_KEY
- - _APP_STORAGE_LINODE_SECRET
- - _APP_STORAGE_LINODE_REGION
- - _APP_STORAGE_LINODE_BUCKET
- - _APP_STORAGE_WASABI_ACCESS_KEY
- - _APP_STORAGE_WASABI_SECRET
- - _APP_STORAGE_WASABI_REGION
- - _APP_STORAGE_WASABI_BUCKET
- - _APP_FUNCTIONS_SIZE_LIMIT
- - _APP_FUNCTIONS_TIMEOUT
- - _APP_FUNCTIONS_BUILD_TIMEOUT
- - _APP_FUNCTIONS_CPUS
- - _APP_FUNCTIONS_MEMORY
- - _APP_FUNCTIONS_RUNTIMES
- - _APP_EXECUTOR_SECRET
- - _APP_EXECUTOR_HOST
- - _APP_LOGGING_CONFIG
- - _APP_MAINTENANCE_INTERVAL
- - _APP_MAINTENANCE_DELAY
- - _APP_MAINTENANCE_RETENTION_EXECUTION
- - _APP_MAINTENANCE_RETENTION_CACHE
- - _APP_MAINTENANCE_RETENTION_ABUSE
- - _APP_MAINTENANCE_RETENTION_AUDIT
- - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- - _APP_MAINTENANCE_RETENTION_SCHEDULES
- - _APP_SMS_PROVIDER
- - _APP_SMS_FROM
- - _APP_GRAPHQL_MAX_BATCH_SIZE
- - _APP_GRAPHQL_MAX_COMPLEXITY
- - _APP_GRAPHQL_MAX_DEPTH
- - _APP_VCS_GITHUB_APP_NAME
- - _APP_VCS_GITHUB_PRIVATE_KEY
- - _APP_VCS_GITHUB_APP_ID
- - _APP_VCS_GITHUB_WEBHOOK_SECRET
- - _APP_VCS_GITHUB_CLIENT_SECRET
- - _APP_VCS_GITHUB_CLIENT_ID
- - _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
- - _APP_ASSISTANT_OPENAI_API_KEY
-
- appwrite-console:
- image: appwrite/console:5.0.12
- container_name: appwrite-console
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- labels:
- - "traefik.enable=true"
- - "traefik.constraint-label-stack=appwrite"
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_LOCALE
- - _APP_CONSOLE_WHITELIST_ROOT
- - _APP_CONSOLE_WHITELIST_EMAILS
- - _APP_CONSOLE_SESSION_ALERTS
- - _APP_CONSOLE_WHITELIST_IPS
- - _APP_CONSOLE_HOSTNAMES
- - _APP_SYSTEM_EMAIL_NAME
- - _APP_SYSTEM_EMAIL_ADDRESS
- - _APP_EMAIL_SECURITY
- - _APP_SYSTEM_RESPONSE_FORMAT
- - _APP_OPTIONS_ABUSE
- - _APP_OPTIONS_ROUTER_PROTECTION
- - _APP_OPTIONS_FORCE_HTTPS
- - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS
- - _APP_OPENSSL_KEY_V1
- - _APP_DOMAIN
- - _APP_DOMAIN_TARGET
- - _APP_DOMAIN_FUNCTIONS
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_SMTP_HOST
- - _APP_SMTP_PORT
- - _APP_SMTP_SECURE
- - _APP_SMTP_USERNAME
- - _APP_SMTP_PASSWORD
- - _APP_USAGE_STATS
- - _APP_STORAGE_LIMIT
- - _APP_STORAGE_PREVIEW_LIMIT
- - _APP_STORAGE_ANTIVIRUS
- - _APP_STORAGE_ANTIVIRUS_HOST
- - _APP_STORAGE_ANTIVIRUS_PORT
- - _APP_STORAGE_DEVICE
- - _APP_STORAGE_S3_ACCESS_KEY
- - _APP_STORAGE_S3_SECRET
- - _APP_STORAGE_S3_REGION
- - _APP_STORAGE_S3_BUCKET
- - _APP_STORAGE_DO_SPACES_ACCESS_KEY
- - _APP_STORAGE_DO_SPACES_SECRET
- - _APP_STORAGE_DO_SPACES_REGION
- - _APP_STORAGE_DO_SPACES_BUCKET
- - _APP_STORAGE_BACKBLAZE_ACCESS_KEY
- - _APP_STORAGE_BACKBLAZE_SECRET
- - _APP_STORAGE_BACKBLAZE_REGION
- - _APP_STORAGE_BACKBLAZE_BUCKET
- - _APP_STORAGE_LINODE_ACCESS_KEY
- - _APP_STORAGE_LINODE_SECRET
- - _APP_STORAGE_LINODE_REGION
- - _APP_STORAGE_LINODE_BUCKET
- - _APP_STORAGE_WASABI_ACCESS_KEY
- - _APP_STORAGE_WASABI_SECRET
- - _APP_STORAGE_WASABI_REGION
- - _APP_STORAGE_WASABI_BUCKET
-
- appwrite-realtime:
- image: appwrite/appwrite:1.6.0
- entrypoint: realtime
- container_name: appwrite-realtime
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - mariadb
- - redis
- labels:
- - "traefik.enable=true"
- - "traefik.constraint-label-stack=appwrite"
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPTIONS_ABUSE
- - _APP_OPTIONS_ROUTER_PROTECTION
- - _APP_OPENSSL_KEY_V1
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_USAGE_STATS
- - _APP_LOGGING_CONFIG
-
- appwrite-worker-audits:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-audits
- <<: *x-logging
- container_name: appwrite-worker-audits
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- - mariadb
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_LOGGING_CONFIG
-
- appwrite-worker-webhooks:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-webhooks
- <<: *x-logging
- container_name: appwrite-worker-webhooks
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- - mariadb
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_EMAIL_SECURITY
- - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_LOGGING_CONFIG
-
- appwrite-worker-deletes:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-deletes
- <<: *x-logging
- container_name: appwrite-worker-deletes
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- - mariadb
- volumes:
- - appwrite-uploads:/storage/uploads:rw
- - appwrite-cache:/storage/cache:rw
- - appwrite-functions:/storage/functions:rw
- - appwrite-builds:/storage/builds:rw
- - appwrite-certificates:/storage/certificates:rw
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_STORAGE_DEVICE
- - _APP_STORAGE_S3_ACCESS_KEY
- - _APP_STORAGE_S3_SECRET
- - _APP_STORAGE_S3_REGION
- - _APP_STORAGE_S3_BUCKET
- - _APP_STORAGE_DO_SPACES_ACCESS_KEY
- - _APP_STORAGE_DO_SPACES_SECRET
- - _APP_STORAGE_DO_SPACES_REGION
- - _APP_STORAGE_DO_SPACES_BUCKET
- - _APP_STORAGE_BACKBLAZE_ACCESS_KEY
- - _APP_STORAGE_BACKBLAZE_SECRET
- - _APP_STORAGE_BACKBLAZE_REGION
- - _APP_STORAGE_BACKBLAZE_BUCKET
- - _APP_STORAGE_LINODE_ACCESS_KEY
- - _APP_STORAGE_LINODE_SECRET
- - _APP_STORAGE_LINODE_REGION
- - _APP_STORAGE_LINODE_BUCKET
- - _APP_STORAGE_WASABI_ACCESS_KEY
- - _APP_STORAGE_WASABI_SECRET
- - _APP_STORAGE_WASABI_REGION
- - _APP_STORAGE_WASABI_BUCKET
- - _APP_LOGGING_CONFIG
- - _APP_EXECUTOR_SECRET
- - _APP_EXECUTOR_HOST
- - _APP_MAINTENANCE_RETENTION_ABUSE
- - _APP_MAINTENANCE_RETENTION_AUDIT
- - _APP_MAINTENANCE_RETENTION_EXECUTION
-
- appwrite-worker-databases:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-databases
- <<: *x-logging
- container_name: appwrite-worker-databases
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- - mariadb
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_LOGGING_CONFIG
-
- appwrite-worker-builds:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-builds
- <<: *x-logging
- container_name: appwrite-worker-builds
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- - mariadb
- volumes:
- - appwrite-functions:/storage/functions:rw
- - appwrite-builds:/storage/builds:rw
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_EXECUTOR_SECRET
- - _APP_EXECUTOR_HOST
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_LOGGING_CONFIG
- - _APP_VCS_GITHUB_APP_NAME
- - _APP_VCS_GITHUB_PRIVATE_KEY
- - _APP_VCS_GITHUB_APP_ID
- - _APP_FUNCTIONS_TIMEOUT
- - _APP_FUNCTIONS_BUILD_TIMEOUT
- - _APP_FUNCTIONS_CPUS
- - _APP_FUNCTIONS_MEMORY
- - _APP_FUNCTIONS_SIZE_LIMIT
- - _APP_OPTIONS_FORCE_HTTPS
- - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS
- - _APP_DOMAIN
- - _APP_STORAGE_DEVICE
- - _APP_STORAGE_S3_ACCESS_KEY
- - _APP_STORAGE_S3_SECRET
- - _APP_STORAGE_S3_REGION
- - _APP_STORAGE_S3_BUCKET
- - _APP_STORAGE_DO_SPACES_ACCESS_KEY
- - _APP_STORAGE_DO_SPACES_SECRET
- - _APP_STORAGE_DO_SPACES_REGION
- - _APP_STORAGE_DO_SPACES_BUCKET
- - _APP_STORAGE_BACKBLAZE_ACCESS_KEY
- - _APP_STORAGE_BACKBLAZE_SECRET
- - _APP_STORAGE_BACKBLAZE_REGION
- - _APP_STORAGE_BACKBLAZE_BUCKET
- - _APP_STORAGE_LINODE_ACCESS_KEY
- - _APP_STORAGE_LINODE_SECRET
- - _APP_STORAGE_LINODE_REGION
- - _APP_STORAGE_LINODE_BUCKET
- - _APP_STORAGE_WASABI_ACCESS_KEY
- - _APP_STORAGE_WASABI_SECRET
- - _APP_STORAGE_WASABI_REGION
- - _APP_STORAGE_WASABI_BUCKET
-
- appwrite-worker-certificates:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-certificates
- <<: *x-logging
- container_name: appwrite-worker-certificates
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- - mariadb
- volumes:
- - appwrite-config:/storage/config:rw
- - appwrite-certificates:/storage/certificates:rw
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_DOMAIN
- - _APP_DOMAIN_TARGET
- - _APP_DOMAIN_FUNCTIONS
- - _APP_EMAIL_CERTIFICATES
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_LOGGING_CONFIG
-
- appwrite-worker-functions:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-functions
- <<: *x-logging
- container_name: appwrite-worker-functions
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- - mariadb
- - openruntimes-executor
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_DOMAIN
- - _APP_OPTIONS_FORCE_HTTPS
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_FUNCTIONS_TIMEOUT
- - _APP_FUNCTIONS_BUILD_TIMEOUT
- - _APP_FUNCTIONS_CPUS
- - _APP_FUNCTIONS_MEMORY
- - _APP_EXECUTOR_SECRET
- - _APP_EXECUTOR_HOST
- - _APP_USAGE_STATS
- - _APP_DOCKER_HUB_USERNAME
- - _APP_DOCKER_HUB_PASSWORD
- - _APP_LOGGING_CONFIG
-
- appwrite-worker-mails:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-mails
- <<: *x-logging
- container_name: appwrite-worker-mails
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_SYSTEM_EMAIL_NAME
- - _APP_SYSTEM_EMAIL_ADDRESS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_SMTP_HOST
- - _APP_SMTP_PORT
- - _APP_SMTP_SECURE
- - _APP_SMTP_USERNAME
- - _APP_SMTP_PASSWORD
- - _APP_LOGGING_CONFIG
-
- appwrite-worker-messaging:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-messaging
- container_name: appwrite-worker-messaging
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- volumes:
- - appwrite-uploads:/storage/uploads:rw
- depends_on:
- - redis
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_LOGGING_CONFIG
- - _APP_SMS_FROM
- - _APP_SMS_PROVIDER
- - _APP_STORAGE_DEVICE
- - _APP_STORAGE_S3_ACCESS_KEY
- - _APP_STORAGE_S3_SECRET
- - _APP_STORAGE_S3_REGION
- - _APP_STORAGE_S3_BUCKET
- - _APP_STORAGE_DO_SPACES_ACCESS_KEY
- - _APP_STORAGE_DO_SPACES_SECRET
- - _APP_STORAGE_DO_SPACES_REGION
- - _APP_STORAGE_DO_SPACES_BUCKET
- - _APP_STORAGE_BACKBLAZE_ACCESS_KEY
- - _APP_STORAGE_BACKBLAZE_SECRET
- - _APP_STORAGE_BACKBLAZE_REGION
- - _APP_STORAGE_BACKBLAZE_BUCKET
- - _APP_STORAGE_LINODE_ACCESS_KEY
- - _APP_STORAGE_LINODE_SECRET
- - _APP_STORAGE_LINODE_REGION
- - _APP_STORAGE_LINODE_BUCKET
- - _APP_STORAGE_WASABI_ACCESS_KEY
- - _APP_STORAGE_WASABI_SECRET
- - _APP_STORAGE_WASABI_REGION
- - _APP_STORAGE_WASABI_BUCKET
-
- appwrite-worker-migrations:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-migrations
- <<: *x-logging
- container_name: appwrite-worker-migrations
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - mariadb
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_DOMAIN
- - _APP_DOMAIN_TARGET
- - _APP_EMAIL_SECURITY
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_LOGGING_CONFIG
- - _APP_MIGRATIONS_FIREBASE_CLIENT_ID
- - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
-
- appwrite-task-maintenance:
- image: appwrite/appwrite:1.6.0
- entrypoint: maintenance
- <<: *x-logging
- container_name: appwrite-task-maintenance
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_DOMAIN
- - _APP_DOMAIN_TARGET
- - _APP_DOMAIN_FUNCTIONS
- - _APP_OPENSSL_KEY_V1
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_MAINTENANCE_INTERVAL
- - _APP_MAINTENANCE_RETENTION_EXECUTION
- - _APP_MAINTENANCE_RETENTION_CACHE
- - _APP_MAINTENANCE_RETENTION_ABUSE
- - _APP_MAINTENANCE_RETENTION_AUDIT
- - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
- - _APP_MAINTENANCE_RETENTION_SCHEDULES
-
- appwrite-worker-usage:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-usage
- container_name: appwrite-worker-usage
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - redis
- - mariadb
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_USAGE_STATS
- - _APP_LOGGING_CONFIG
- - _APP_USAGE_AGGREGATION_INTERVAL
-
- appwrite-worker-usage-dump:
- image: appwrite/appwrite:1.6.0
- entrypoint: worker-usage-dump
- container_name: appwrite-worker-usage-dump
- <<: *x-logging
- networks:
- - dokploy-network
- depends_on:
- - redis
- - mariadb
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_USAGE_STATS
- - _APP_LOGGING_CONFIG
- - _APP_USAGE_AGGREGATION_INTERVAL
-
- appwrite-task-scheduler-functions:
- image: appwrite/appwrite:1.6.0
- entrypoint: schedule-functions
- container_name: appwrite-task-scheduler-functions
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - mariadb
- - redis
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
-
- appwrite-task-scheduler-executions:
- image: appwrite/appwrite:1.6.0
- entrypoint: schedule-executions
- container_name: appwrite-task-scheduler-executions
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - mariadb
- - redis
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
-
- appwrite-task-scheduler-messages:
- image: appwrite/appwrite:1.6.0
- entrypoint: schedule-messages
- container_name: appwrite-task-scheduler-messages
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- depends_on:
- - mariadb
- - redis
- environment:
- - _APP_ENV
- - _APP_WORKER_PER_CORE
- - _APP_OPENSSL_KEY_V1
- - _APP_REDIS_HOST
- - _APP_REDIS_PORT
- - _APP_REDIS_USER
- - _APP_REDIS_PASS
- - _APP_DB_HOST
- - _APP_DB_PORT
- - _APP_DB_SCHEMA
- - _APP_DB_USER
- - _APP_DB_PASS
-
- appwrite-assistant:
- image: appwrite/assistant:0.4.0
- container_name: appwrite-assistant
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- environment:
- - _APP_ASSISTANT_OPENAI_API_KEY
-
- openruntimes-executor:
- container_name: openruntimes-executor
- hostname: exc1
- <<: *x-logging
- restart: unless-stopped
- stop_signal: SIGINT
- image: openruntimes/executor:0.6.11
- networks:
- - dokploy-network
- volumes:
- - /var/run/docker.sock:/var/run/docker.sock
- - appwrite-builds:/storage/builds:rw
- - appwrite-functions:/storage/functions:rw
- - /tmp:/tmp:rw
- environment:
- - OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_FUNCTIONS_INACTIVE_THRESHOLD
- - OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_FUNCTIONS_MAINTENANCE_INTERVAL
- - OPR_EXECUTOR_NETWORK=$_APP_FUNCTIONS_RUNTIMES_NETWORK
- - OPR_EXECUTOR_DOCKER_HUB_USERNAME=$_APP_DOCKER_HUB_USERNAME
- - OPR_EXECUTOR_DOCKER_HUB_PASSWORD=$_APP_DOCKER_HUB_PASSWORD
- - OPR_EXECUTOR_ENV=$_APP_ENV
- - OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES
- - OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
- - OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
- - OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE
- - OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY
- - OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET
- - OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION
- - OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET
- - OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY
- - OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET
- - OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION
- - OPR_EXECUTOR_STORAGE_DO_SPACES_BUCKET=$_APP_STORAGE_DO_SPACES_BUCKET
- - OPR_EXECUTOR_STORAGE_BACKBLAZE_ACCESS_KEY=$_APP_STORAGE_BACKBLAZE_ACCESS_KEY
- - OPR_EXECUTOR_STORAGE_BACKBLAZE_SECRET=$_APP_STORAGE_BACKBLAZE_SECRET
- - OPR_EXECUTOR_STORAGE_BACKBLAZE_REGION=$_APP_STORAGE_BACKBLAZE_REGION
- - OPR_EXECUTOR_STORAGE_BACKBLAZE_BUCKET=$_APP_STORAGE_BACKBLAZE_BUCKET
- - OPR_EXECUTOR_STORAGE_LINODE_ACCESS_KEY=$_APP_STORAGE_LINODE_ACCESS_KEY
- - OPR_EXECUTOR_STORAGE_LINODE_SECRET=$_APP_STORAGE_LINODE_SECRET
- - OPR_EXECUTOR_STORAGE_LINODE_REGION=$_APP_STORAGE_LINODE_REGION
- - OPR_EXECUTOR_STORAGE_LINODE_BUCKET=$_APP_STORAGE_LINODE_BUCKET
- - OPR_EXECUTOR_STORAGE_WASABI_ACCESS_KEY=$_APP_STORAGE_WASABI_ACCESS_KEY
- - OPR_EXECUTOR_STORAGE_WASABI_SECRET=$_APP_STORAGE_WASABI_SECRET
- - OPR_EXECUTOR_STORAGE_WASABI_REGION=$_APP_STORAGE_WASABI_REGION
- - OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET
-
- mariadb:
- image: mariadb:10.11
- container_name: appwrite-mariadb
- <<: *x-logging
- restart: unless-stopped
- networks:
- - dokploy-network
- volumes:
- - appwrite-mariadb:/var/lib/mysql:rw
- environment:
- - MYSQL_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
- - MYSQL_DATABASE=${_APP_DB_SCHEMA}
- - MYSQL_USER=${_APP_DB_USER}
- - MYSQL_PASSWORD=${_APP_DB_PASS}
- - MARIADB_AUTO_UPGRADE=1
- command: "mysqld --innodb-flush-method=fsync"
-
- redis:
- image: redis:7.2.4-alpine
- container_name: appwrite-redis
- <<: *x-logging
- restart: unless-stopped
- command: >
- redis-server
- --maxmemory 512mb
- --maxmemory-policy allkeys-lru
- --maxmemory-samples 5
- networks:
- - dokploy-network
- volumes:
- - appwrite-redis:/data:rw
-
-# Uncomment and configure if ClamAV is needed
-# clamav:
-# image: appwrite/clamav:1.2.0
-# container_name: appwrite-clamav
-# restart: unless-stopped
-# networks:
-# - dokploy-network
-# volumes:
-# - appwrite-uploads:/storage/uploads
-
-volumes:
- appwrite-mariadb:
- appwrite-redis:
- appwrite-cache:
- appwrite-uploads:
- appwrite-certificates:
- appwrite-functions:
- appwrite-builds:
- appwrite-config:
-
-networks:
- dokploy-network:
- external: true
diff --git a/apps/dokploy/templates/appwrite/index.ts b/apps/dokploy/templates/appwrite/index.ts
deleted file mode 100644
index 4e671324..00000000
--- a/apps/dokploy/templates/appwrite/index.ts
+++ /dev/null
@@ -1,153 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
-
- const domains: DomainSchema[] = [
- { host: mainDomain, port: 80, serviceName: "appwrite", path: "/" },
- {
- host: mainDomain,
- port: 80,
- serviceName: "appwrite-console",
- path: "/console",
- },
- {
- host: mainDomain,
- port: 80,
- serviceName: "appwrite-realtime",
- path: "/v1/realtime",
- },
- ];
-
- const envs = [
- "_APP_ENV=production",
- "_APP_LOCALE=en",
- "_APP_OPTIONS_ABUSE=enabled",
- "_APP_OPTIONS_FORCE_HTTPS=disabled",
- "_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS=disabled",
- "_APP_OPTIONS_ROUTER_PROTECTION=disabled",
- "_APP_OPENSSL_KEY_V1=your-secret-key",
- `_APP_DOMAIN=${mainDomain}`,
- `_APP_DOMAIN_FUNCTIONS=${mainDomain}`,
- `_APP_DOMAIN_TARGET=${mainDomain}`,
- "_APP_CONSOLE_WHITELIST_ROOT=enabled",
- "_APP_CONSOLE_WHITELIST_EMAILS=",
- "_APP_CONSOLE_WHITELIST_IPS=",
- "_APP_CONSOLE_HOSTNAMES=",
- "_APP_SYSTEM_EMAIL_NAME=Appwrite",
- "_APP_SYSTEM_EMAIL_ADDRESS=noreply@appwrite.io",
- "_APP_SYSTEM_TEAM_EMAIL=team@appwrite.io",
- "_APP_SYSTEM_RESPONSE_FORMAT=",
- "_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=certs@appwrite.io",
- "_APP_EMAIL_SECURITY=",
- "_APP_EMAIL_CERTIFICATES=",
- "_APP_USAGE_STATS=enabled",
- "_APP_LOGGING_PROVIDER=",
- "_APP_LOGGING_CONFIG=",
- "_APP_USAGE_AGGREGATION_INTERVAL=30",
- "_APP_USAGE_TIMESERIES_INTERVAL=30",
- "_APP_USAGE_DATABASE_INTERVAL=900",
- "_APP_WORKER_PER_CORE=6",
- "_APP_CONSOLE_SESSION_ALERTS=disabled",
- "_APP_REDIS_HOST=redis",
- "_APP_REDIS_PORT=6379",
- "_APP_REDIS_USER=",
- "_APP_REDIS_PASS=",
- "_APP_DB_HOST=mariadb",
- "_APP_DB_PORT=3306",
- "_APP_DB_SCHEMA=appwrite",
- "_APP_DB_USER=user",
- "_APP_DB_PASS=password",
- "_APP_DB_ROOT_PASS=rootsecretpassword",
- "_APP_INFLUXDB_HOST=influxdb",
- "_APP_INFLUXDB_PORT=8086",
- "_APP_STATSD_HOST=telegraf",
- "_APP_STATSD_PORT=8125",
- "_APP_SMTP_HOST=",
- "_APP_SMTP_PORT=",
- "_APP_SMTP_SECURE=",
- "_APP_SMTP_USERNAME=",
- "_APP_SMTP_PASSWORD=",
- "_APP_SMS_PROVIDER=",
- "_APP_SMS_FROM=",
- "_APP_STORAGE_LIMIT=30000000",
- "_APP_STORAGE_PREVIEW_LIMIT=20000000",
- "_APP_STORAGE_ANTIVIRUS=disabled",
- "_APP_STORAGE_ANTIVIRUS_HOST=clamav",
- "_APP_STORAGE_ANTIVIRUS_PORT=3310",
- "_APP_STORAGE_DEVICE=local",
- "_APP_STORAGE_S3_ACCESS_KEY=",
- "_APP_STORAGE_S3_SECRET=",
- "_APP_STORAGE_S3_REGION=us-east-1",
- "_APP_STORAGE_S3_BUCKET=",
- "_APP_STORAGE_DO_SPACES_ACCESS_KEY=",
- "_APP_STORAGE_DO_SPACES_SECRET=",
- "_APP_STORAGE_DO_SPACES_REGION=us-east-1",
- "_APP_STORAGE_DO_SPACES_BUCKET=",
- "_APP_STORAGE_BACKBLAZE_ACCESS_KEY=",
- "_APP_STORAGE_BACKBLAZE_SECRET=",
- "_APP_STORAGE_BACKBLAZE_REGION=us-west-004",
- "_APP_STORAGE_BACKBLAZE_BUCKET=",
- "_APP_STORAGE_LINODE_ACCESS_KEY=",
- "_APP_STORAGE_LINODE_SECRET=",
- "_APP_STORAGE_LINODE_REGION=eu-central-1",
- "_APP_STORAGE_LINODE_BUCKET=",
- "_APP_STORAGE_WASABI_ACCESS_KEY=",
- "_APP_STORAGE_WASABI_SECRET=",
- "_APP_STORAGE_WASABI_REGION=eu-central-1",
- "_APP_STORAGE_WASABI_BUCKET=",
- "_APP_FUNCTIONS_SIZE_LIMIT=30000000",
- "_APP_FUNCTIONS_BUILD_SIZE_LIMIT=2000000000",
- "_APP_FUNCTIONS_TIMEOUT=900",
- "_APP_FUNCTIONS_BUILD_TIMEOUT=900",
- "_APP_FUNCTIONS_CONTAINERS=10",
- "_APP_FUNCTIONS_CPUS=0",
- "_APP_FUNCTIONS_MEMORY=0",
- "_APP_FUNCTIONS_MEMORY_SWAP=0",
- "_APP_FUNCTIONS_RUNTIMES=node-16.0,php-8.0,python-3.9,ruby-3.0",
- "_APP_EXECUTOR_SECRET=your-secret-key",
- "_APP_EXECUTOR_HOST=http://exc1/v1",
- "_APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes",
- "_APP_FUNCTIONS_ENVS=node-16.0,php-7.4,python-3.9,ruby-3.0",
- "_APP_FUNCTIONS_INACTIVE_THRESHOLD=60",
- "DOCKERHUB_PULL_USERNAME=",
- "DOCKERHUB_PULL_PASSWORD=",
- "DOCKERHUB_PULL_EMAIL=",
- "OPEN_RUNTIMES_NETWORK=appwrite_runtimes",
- "_APP_FUNCTIONS_RUNTIMES_NETWORK=runtimes",
- "_APP_DOCKER_HUB_USERNAME=",
- "_APP_DOCKER_HUB_PASSWORD=",
- "_APP_FUNCTIONS_MAINTENANCE_INTERVAL=3600",
- "_APP_VCS_GITHUB_APP_NAME=",
- "_APP_VCS_GITHUB_PRIVATE_KEY=",
- "_APP_VCS_GITHUB_APP_ID=",
- "_APP_VCS_GITHUB_CLIENT_ID=",
- "_APP_VCS_GITHUB_CLIENT_SECRET=",
- "_APP_VCS_GITHUB_WEBHOOK_SECRET=",
- "_APP_MAINTENANCE_INTERVAL=86400",
- "_APP_MAINTENANCE_DELAY=0",
- "_APP_MAINTENANCE_RETENTION_CACHE=2592000",
- "_APP_MAINTENANCE_RETENTION_EXECUTION=1209600",
- "_APP_MAINTENANCE_RETENTION_AUDIT=1209600",
- "_APP_MAINTENANCE_RETENTION_ABUSE=86400",
- "_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000",
- "_APP_MAINTENANCE_RETENTION_SCHEDULES=86400",
- "_APP_GRAPHQL_MAX_BATCH_SIZE=10",
- "_APP_GRAPHQL_MAX_COMPLEXITY=250",
- "_APP_GRAPHQL_MAX_DEPTH=3",
- "_APP_MIGRATIONS_FIREBASE_CLIENT_ID=",
- "_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET=",
- "_APP_ASSISTANT_OPENAI_API_KEY=",
- ];
-
- return {
- domains,
- envs,
- mounts: [],
- };
-}
diff --git a/apps/dokploy/templates/aptabase/docker-compose.yml b/apps/dokploy/templates/aptabase/docker-compose.yml
index dfde1cae..934fd1ee 100644
--- a/apps/dokploy/templates/aptabase/docker-compose.yml
+++ b/apps/dokploy/templates/aptabase/docker-compose.yml
@@ -7,7 +7,8 @@ services:
environment:
POSTGRES_USER: aptabase
POSTGRES_PASSWORD: sTr0NGp4ssw0rd
-
+ networks:
+ - dokploy-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U aptabase"]
interval: 10s
@@ -26,7 +27,8 @@ services:
nofile:
soft: 262144
hard: 262144
-
+ networks:
+ - dokploy-network
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8123 || exit 1"]
interval: 10s
diff --git a/apps/dokploy/templates/blender/index.ts b/apps/dokploy/templates/blender/index.ts
index 79508bed..84e52755 100644
--- a/apps/dokploy/templates/blender/index.ts
+++ b/apps/dokploy/templates/blender/index.ts
@@ -7,7 +7,7 @@ import {
} from "../utils";
export function generate(schema: Schema): Template {
- const _mainServiceHash = generateHash(schema.projectName);
+ const mainServiceHash = generateHash(schema.projectName);
const mainDomain = generateRandomDomain(schema);
const domains: DomainSchema[] = [
diff --git a/apps/dokploy/templates/budibase/docker-compose.yml b/apps/dokploy/templates/budibase/docker-compose.yml
index d1d6744a..3f82de3e 100644
--- a/apps/dokploy/templates/budibase/docker-compose.yml
+++ b/apps/dokploy/templates/budibase/docker-compose.yml
@@ -2,7 +2,8 @@ services:
apps:
image: budibase.docker.scarf.sh/budibase/apps:3.2.25
restart: unless-stopped
-
+ networks:
+ - dokploy-network
environment:
SELF_HOSTED: 1
LOG_LEVEL: info
@@ -42,7 +43,8 @@ services:
worker:
image: budibase.docker.scarf.sh/budibase/worker:3.2.25
restart: unless-stopped
-
+ networks:
+ - dokploy-network
environment:
SELF_HOSTED: 1
LOG_LEVEL: info
@@ -81,7 +83,8 @@ services:
minio:
image: minio/minio:RELEASE.2024-11-07T00-52-20Z
restart: unless-stopped
-
+ networks:
+ - dokploy-network
volumes:
- 'minio_data:/data'
environment:
@@ -101,7 +104,8 @@ services:
proxy:
image: budibase/proxy:3.2.25
restart: unless-stopped
-
+ networks:
+ - dokploy-network
environment:
PROXY_RATE_LIMIT_WEBHOOKS_PER_SECOND: 10
PROXY_RATE_LIMIT_API_PER_SECOND: 20
@@ -133,7 +137,8 @@ services:
couchdb:
image: budibase/couchdb:v3.3.3
restart: unless-stopped
-
+ networks:
+ - dokploy-network
environment:
COUCHDB_USER: budibase
COUCHDB_PASSWORD: ${BB_COUCHDB_PASSWORD}
@@ -152,7 +157,8 @@ services:
- 'couchdb3_data:/opt/couchdb/data'
redis:
image: redis:7.2-alpine
-
+ networks:
+ - dokploy-network
restart: unless-stopped
command: 'redis-server --requirepass "${BB_REDIS_PASSWORD}"'
volumes:
@@ -170,7 +176,8 @@ services:
start_period: 10s
watchtower:
restart: unless-stopped
-
+ networks:
+ - dokploy-network
image: containrrr/watchtower:1.7.1
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
diff --git a/apps/dokploy/templates/calcom/docker-compose.yml b/apps/dokploy/templates/calcom/docker-compose.yml
index a309a1da..7a1d8c92 100644
--- a/apps/dokploy/templates/calcom/docker-compose.yml
+++ b/apps/dokploy/templates/calcom/docker-compose.yml
@@ -1,7 +1,8 @@
services:
postgres:
image: postgres:16-alpine
-
+ networks:
+ - dokploy-network
volumes:
- calcom-data:/var/lib/postgresql/data
environment:
diff --git a/apps/dokploy/templates/chatwoot/docker-compose.yml b/apps/dokploy/templates/chatwoot/docker-compose.yml
index b24ca0b5..8b762e36 100644
--- a/apps/dokploy/templates/chatwoot/docker-compose.yml
+++ b/apps/dokploy/templates/chatwoot/docker-compose.yml
@@ -51,7 +51,8 @@ services:
restart: always
volumes:
- chatwoot-postgres-data:/var/lib/postgresql/data
-
+ networks:
+ - dokploy-network
environment:
- POSTGRES_DB=${POSTGRES_DATABASE}
- POSTGRES_USER=${POSTGRES_USERNAME}
@@ -62,7 +63,8 @@ services:
restart: always
volumes:
- chatwoot-redis-data:/data
-
+ networks:
+ - dokploy-network
networks:
dokploy-network:
diff --git a/apps/dokploy/templates/checkmate/docker-compose.yml b/apps/dokploy/templates/checkmate/docker-compose.yml
index 7a5fc898..dc83a28f 100644
--- a/apps/dokploy/templates/checkmate/docker-compose.yml
+++ b/apps/dokploy/templates/checkmate/docker-compose.yml
@@ -9,7 +9,8 @@ services:
- 443
depends_on:
- server
-
+ networks:
+ - dokploy-network
server:
image: bluewaveuptime/uptime_server:latest
restart: always
@@ -21,7 +22,8 @@ services:
environment:
- DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db
- REDIS_HOST=redis
-
+ networks:
+ - dokploy-network
# volumes:
# - /var/run/docker.sock:/var/run/docker.sock:ro
redis:
@@ -31,7 +33,8 @@ services:
- 6379
volumes:
- ../files/redis/data:/data
-
+ networks:
+ - dokploy-network
mongodb:
image: bluewaveuptime/uptime_database_mongo:latest
restart: always
@@ -40,3 +43,5 @@ services:
command: ["mongod", "--quiet"]
ports:
- 27017
+ networks:
+ - dokploy-network
\ No newline at end of file
diff --git a/apps/dokploy/templates/cloudflared/index.ts b/apps/dokploy/templates/cloudflared/index.ts
index 93ea091c..661fa31d 100644
--- a/apps/dokploy/templates/cloudflared/index.ts
+++ b/apps/dokploy/templates/cloudflared/index.ts
@@ -1,6 +1,6 @@
import type { Schema, Template } from "../utils";
-export function generate(_schema: Schema): Template {
+export function generate(schema: Schema): Template {
const envs = [`CLOUDFLARE_TUNNEL_TOKEN=""`];
return {
diff --git a/apps/dokploy/templates/coder/docker-compose.yml b/apps/dokploy/templates/coder/docker-compose.yml
index 875c7ae8..27bb14bd 100644
--- a/apps/dokploy/templates/coder/docker-compose.yml
+++ b/apps/dokploy/templates/coder/docker-compose.yml
@@ -1,7 +1,8 @@
services:
coder:
image: ghcr.io/coder/coder:v2.15.3
-
+ networks:
+ - dokploy-network
volumes:
- /var/run/docker.sock:/var/run/docker.sock
group_add:
@@ -16,7 +17,8 @@ services:
db:
image: postgres:17
-
+ networks:
+ - dokploy-network
environment:
- POSTGRES_PASSWORD
- POSTGRES_USER
diff --git a/apps/dokploy/templates/convex/docker-compose.yml b/apps/dokploy/templates/convex/docker-compose.yml
deleted file mode 100644
index 12e2b5ad..00000000
--- a/apps/dokploy/templates/convex/docker-compose.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-services:
- backend:
- image: ghcr.io/get-convex/convex-backend:6c974d219776b753cd23d26f4a296629ff7c2cad
- ports:
- - "${PORT:-3210}:3210"
- - "${SITE_PROXY_PORT:-3211}:3211"
- volumes:
- - data:/convex/data
- environment:
- - INSTANCE_NAME=${INSTANCE_NAME:-}
- - INSTANCE_SECRET=${INSTANCE_SECRET:-}
- - CONVEX_RELEASE_VERSION_DEV=${CONVEX_RELEASE_VERSION_DEV:-}
- - ACTIONS_USER_TIMEOUT_SECS=${ACTIONS_USER_TIMEOUT_SECS:-}
- - CONVEX_CLOUD_ORIGIN=${CONVEX_CLOUD_ORIGIN:-http://127.0.0.1:3210}
- - CONVEX_SITE_ORIGIN=${CONVEX_SITE_ORIGIN:-http://127.0.0.1:3211}
- - DATABASE_URL=${DATABASE_URL:-}
- - DISABLE_BEACON=${DISABLE_BEACON:-}
- - REDACT_LOGS_TO_CLIENT=${REDACT_LOGS_TO_CLIENT:-}
- - RUST_LOG=${RUST_LOG:-info}
- - RUST_BACKTRACE=${RUST_BACKTRACE:-}
- healthcheck:
- test: curl -f http://localhost:3210/version
- interval: 5s
- start_period: 5s
-
- dashboard:
- image: ghcr.io/get-convex/convex-dashboard:4499dd4fd7f2148687a7774599c613d052950f46
- ports:
- - "${DASHBOARD_PORT:-6791}:6791"
- environment:
- - NEXT_PUBLIC_DEPLOYMENT_URL=${NEXT_PUBLIC_DEPLOYMENT_URL:-http://127.0.0.1:3210}
- depends_on:
- backend:
- condition: service_healthy
-
-volumes:
- data:
diff --git a/apps/dokploy/templates/convex/index.ts b/apps/dokploy/templates/convex/index.ts
deleted file mode 100644
index badfe732..00000000
--- a/apps/dokploy/templates/convex/index.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const dashboardDomain = generateRandomDomain(schema);
- const backendDomain = generateRandomDomain(schema);
- const actionsDomain = generateRandomDomain(schema);
-
- const domains: DomainSchema[] = [
- {
- host: dashboardDomain,
- port: 6791,
- serviceName: "dashboard",
- },
- {
- host: backendDomain,
- port: 3210,
- serviceName: "backend",
- },
- {
- host: actionsDomain,
- port: 3211,
- serviceName: "backend",
- },
- ];
-
- const envs = [
- `NEXT_PUBLIC_DEPLOYMENT_URL=http://${backendDomain}`,
- `CONVEX_CLOUD_ORIGIN=http://${backendDomain}`,
- `CONVEX_SITE_ORIGIN=http://${actionsDomain}`,
- ];
-
- return { envs, domains };
-}
diff --git a/apps/dokploy/templates/directus/docker-compose.yml b/apps/dokploy/templates/directus/docker-compose.yml
index 52e64baf..20f1b45d 100644
--- a/apps/dokploy/templates/directus/docker-compose.yml
+++ b/apps/dokploy/templates/directus/docker-compose.yml
@@ -3,7 +3,8 @@ services:
image: postgis/postgis:13-master
volumes:
- directus_database:/var/lib/postgresql/data
-
+ networks:
+ - dokploy-network
environment:
POSTGRES_USER: "directus"
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
@@ -25,7 +26,8 @@ services:
retries: 5
start_interval: 5s
start_period: 30s
-
+ networks:
+ - dokploy-network
directus:
image: directus/directus:11.0.2
diff --git a/apps/dokploy/templates/discord-tickets/docker-compose.yml b/apps/dokploy/templates/discord-tickets/docker-compose.yml
index f797a77b..e6e41288 100644
--- a/apps/dokploy/templates/discord-tickets/docker-compose.yml
+++ b/apps/dokploy/templates/discord-tickets/docker-compose.yml
@@ -4,7 +4,8 @@ services:
tickets-postgres:
image: mysql:8
restart: unless-stopped
-
+ networks:
+ - dokploy-network
volumes:
- tickets-mysql-data:/var/lib/mysql
environment:
@@ -24,7 +25,8 @@ services:
tickets-postgres:
condition: service_healthy
restart: unless-stopped
-
+ networks:
+ - dokploy-network
volumes:
- tickets-app-data:/home/container/user
- /etc/timezone:/etc/timezone:ro
diff --git a/apps/dokploy/templates/discourse/docker-compose.yml b/apps/dokploy/templates/discourse/docker-compose.yml
index 2b938b85..ce6106be 100644
--- a/apps/dokploy/templates/discourse/docker-compose.yml
+++ b/apps/dokploy/templates/discourse/docker-compose.yml
@@ -3,7 +3,8 @@ version: '3.7'
services:
discourse-db:
image: docker.io/bitnami/postgresql:17
-
+ networks:
+ - dokploy-network
volumes:
- discourse-postgresql-data:/bitnami/postgresql
environment:
@@ -19,7 +20,8 @@ services:
discourse-redis:
image: docker.io/bitnami/redis:7.4
-
+ networks:
+ - dokploy-network
volumes:
- discourse-redis-data:/bitnami/redis
environment:
@@ -33,7 +35,8 @@ services:
discourse-app:
image: docker.io/bitnami/discourse:3.3.2
-
+ networks:
+ - dokploy-network
volumes:
- discourse-data:/bitnami/discourse
depends_on:
@@ -60,7 +63,8 @@ services:
discourse-sidekiq:
image: docker.io/bitnami/discourse:3.3.2
-
+ networks:
+ - dokploy-network
volumes:
- discourse-sidekiq-data:/bitnami/discourse
depends_on:
diff --git a/apps/dokploy/templates/docmost/docker-compose.yml b/apps/dokploy/templates/docmost/docker-compose.yml
index b5995594..a6ebbd4f 100644
--- a/apps/dokploy/templates/docmost/docker-compose.yml
+++ b/apps/dokploy/templates/docmost/docker-compose.yml
@@ -12,7 +12,8 @@ services:
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public
- REDIS_URL=redis://redis:6379
restart: unless-stopped
-
+ networks:
+ - dokploy-network
volumes:
- docmost:/app/data/storage
@@ -23,14 +24,16 @@ services:
- POSTGRES_USER
- POSTGRES_PASSWORD
restart: unless-stopped
-
+ networks:
+ - dokploy-network
volumes:
- db_docmost_data:/var/lib/postgresql/data
redis:
image: redis:7.2-alpine
restart: unless-stopped
-
+ networks:
+ - dokploy-network
volumes:
- redis_docmost_data:/data
diff --git a/apps/dokploy/templates/documenso/docker-compose.yml b/apps/dokploy/templates/documenso/docker-compose.yml
index 9b8e8ed8..562fe498 100644
--- a/apps/dokploy/templates/documenso/docker-compose.yml
+++ b/apps/dokploy/templates/documenso/docker-compose.yml
@@ -2,7 +2,8 @@ version: "3.8"
services:
postgres:
image: postgres:16
-
+ networks:
+ - dokploy-network
volumes:
- documenso-data:/var/lib/postgresql/data
environment:
diff --git a/apps/dokploy/templates/drawio/docker-compose.yml b/apps/dokploy/templates/drawio/docker-compose.yml
index a7d7b578..1712363f 100644
--- a/apps/dokploy/templates/drawio/docker-compose.yml
+++ b/apps/dokploy/templates/drawio/docker-compose.yml
@@ -4,14 +4,16 @@ services:
image: plantuml/plantuml-server
ports:
- "8080"
-
+ networks:
+ - dokploy-network
volumes:
- fonts_volume:/usr/share/fonts/drawio
image-export:
image: jgraph/export-server
ports:
- "8000"
-
+ networks:
+ - dokploy-network
volumes:
- fonts_volume:/usr/share/fonts/drawio
environment:
@@ -26,7 +28,8 @@ services:
depends_on:
- plantuml-server
- image-export
-
+ networks:
+ - dokploy-network
environment:
RAWIO_SELF_CONTAINED: 1
DRAWIO_USE_HTTP: 1
diff --git a/apps/dokploy/templates/drawio/index.ts b/apps/dokploy/templates/drawio/index.ts
index 701283c8..e3c57c5a 100644
--- a/apps/dokploy/templates/drawio/index.ts
+++ b/apps/dokploy/templates/drawio/index.ts
@@ -8,7 +8,7 @@ import {
export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema);
- const _secretKeyBase = generateBase64(64);
+ const secretKeyBase = generateBase64(64);
const domains: DomainSchema[] = [
{
diff --git a/apps/dokploy/templates/erpnext/docker-compose.yml b/apps/dokploy/templates/erpnext/docker-compose.yml
deleted file mode 100644
index 28cd8f6a..00000000
--- a/apps/dokploy/templates/erpnext/docker-compose.yml
+++ /dev/null
@@ -1,354 +0,0 @@
-x-custom-image: &custom_image
- image: ${IMAGE_NAME:-docker.io/frappe/erpnext}:${VERSION:-version-15}
- pull_policy: ${PULL_POLICY:-always}
- deploy:
- restart_policy:
- condition: always
-
-services:
- backend:
- <<: *custom_image
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - '0.0.0.0:8000'
- interval: 2s
- timeout: 10s
- retries: 30
-
- frontend:
- <<: *custom_image
- command:
- - nginx-entrypoint.sh
- depends_on:
- backend:
- condition: service_started
- required: true
- websocket:
- condition: service_started
- required: true
- environment:
- BACKEND: backend:8000
- FRAPPE_SITE_NAME_HEADER: ${FRAPPE_SITE_NAME_HEADER:-$$host}
- SOCKETIO: websocket:9000
- UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1
- UPSTREAM_REAL_IP_HEADER: X-Forwarded-For
- UPSTREAM_REAL_IP_RECURSIVE: "off"
- volumes:
- - sites:/home/frappe/frappe-bench/sites
-
- networks:
- - bench-network
-
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - '0.0.0.0:8080'
- interval: 2s
- timeout: 30s
- retries: 30
-
- queue-default:
- <<: *custom_image
- command:
- - bench
- - worker
- - --queue
- - default
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - 'redis-queue:6379'
- interval: 2s
- timeout: 10s
- retries: 30
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
-
- queue-long:
- <<: *custom_image
- command:
- - bench
- - worker
- - --queue
- - long
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - 'redis-queue:6379'
- interval: 2s
- timeout: 10s
- retries: 30
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
-
- queue-short:
- <<: *custom_image
- command:
- - bench
- - worker
- - --queue
- - short
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - 'redis-queue:6379'
- interval: 2s
- timeout: 10s
- retries: 30
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
-
- scheduler:
- <<: *custom_image
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - 'redis-queue:6379'
- interval: 2s
- timeout: 10s
- retries: 30
- command:
- - bench
- - schedule
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
-
- websocket:
- <<: *custom_image
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - '0.0.0.0:9000'
- interval: 2s
- timeout: 10s
- retries: 30
- command:
- - node
- - /home/frappe/frappe-bench/apps/frappe/socketio.js
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
-
- configurator:
- <<: *custom_image
- deploy:
- mode: replicated
- replicas: ${CONFIGURE:-0}
- restart_policy:
- condition: none
- entrypoint: ["bash", "-c"]
- command:
- - >
- [[ $${REGENERATE_APPS_TXT} == "1" ]] && ls -1 apps > sites/apps.txt;
- [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && exit 0;
- bench set-config -g db_host $$DB_HOST;
- bench set-config -gp db_port $$DB_PORT;
- bench set-config -g redis_cache "redis://$$REDIS_CACHE";
- bench set-config -g redis_queue "redis://$$REDIS_QUEUE";
- bench set-config -g redis_socketio "redis://$$REDIS_QUEUE";
- bench set-config -gp socketio_port $$SOCKETIO_PORT;
- environment:
- DB_HOST: "${DB_HOST:-db}"
- DB_PORT: "3306"
- REDIS_CACHE: redis-cache:6379
- REDIS_QUEUE: redis-queue:6379
- SOCKETIO_PORT: "9000"
- REGENERATE_APPS_TXT: "${REGENERATE_APPS_TXT:-0}"
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
-
- create-site:
- <<: *custom_image
- deploy:
- mode: replicated
- replicas: ${CREATE_SITE:-0}
- restart_policy:
- condition: none
- entrypoint: ["bash", "-c"]
- command:
- - >
- wait-for-it -t 120 $$DB_HOST:$$DB_PORT;
- wait-for-it -t 120 redis-cache:6379;
- wait-for-it -t 120 redis-queue:6379;
- export start=`date +%s`;
- until [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && \
- [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty"` ]] && \
- [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty"` ]];
- do
- echo "Waiting for sites/common_site_config.json to be created";
- sleep 5;
- if (( `date +%s`-start > 120 )); then
- echo "could not find sites/common_site_config.json with required keys";
- exit 1
- fi
- done;
- echo "sites/common_site_config.json found";
- [[ -d "sites/${SITE_NAME}" ]] && echo "${SITE_NAME} already exists" && exit 0;
- bench new-site --mariadb-user-host-login-scope='%' --admin-password=$${ADMIN_PASSWORD} --db-root-username=root --db-root-password=$${DB_ROOT_PASSWORD} $${INSTALL_APP_ARGS} $${SITE_NAME};
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- environment:
- SITE_NAME: ${SITE_NAME}
- ADMIN_PASSWORD: ${ADMIN_PASSWORD}
- DB_HOST: ${DB_HOST:-db}
- DB_PORT: "${DB_PORT:-3306}"
- DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
- INSTALL_APP_ARGS: ${INSTALL_APP_ARGS}
- networks:
- - bench-network
-
- migration:
- <<: *custom_image
- deploy:
- mode: replicated
- replicas: ${MIGRATE:-0}
- restart_policy:
- condition: none
- entrypoint: ["bash", "-c"]
- command:
- - >
- curl -f http://${SITE_NAME}:8080/api/method/ping || echo "Site busy" && exit 0;
- bench --site all set-config -p maintenance_mode 1;
- bench --site all set-config -p pause_scheduler 1;
- bench --site all migrate;
- bench --site all set-config -p maintenance_mode 0;
- bench --site all set-config -p pause_scheduler 0;
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
-
- db:
- image: mariadb:10.6
- deploy:
- mode: replicated
- replicas: ${ENABLE_DB:-0}
- restart_policy:
- condition: always
- healthcheck:
- test: mysqladmin ping -h localhost --password=${DB_ROOT_PASSWORD}
- interval: 1s
- retries: 20
- command:
- - --character-set-server=utf8mb4
- - --collation-server=utf8mb4_unicode_ci
- - --skip-character-set-client-handshake
- - --skip-innodb-read-only-compressed
- environment:
- - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- - MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- volumes:
- - db-data:/var/lib/mysql
- networks:
- - bench-network
-
- redis-cache:
- deploy:
- restart_policy:
- condition: always
- image: redis:6.2-alpine
- volumes:
- - redis-cache-data:/data
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - redis-cli
- - ping
- interval: 5s
- timeout: 5s
- retries: 3
-
- redis-queue:
- deploy:
- restart_policy:
- condition: always
- image: redis:6.2-alpine
- volumes:
- - redis-queue-data:/data
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - redis-cli
- - ping
- interval: 5s
- timeout: 5s
- retries: 3
-
- redis-socketio:
- deploy:
- restart_policy:
- condition: always
- image: redis:6.2-alpine
- volumes:
- - redis-socketio-data:/data
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - redis-cli
- - ping
- interval: 5s
- timeout: 5s
- retries: 3
-
-volumes:
- db-data:
- redis-cache-data:
- redis-queue-data:
- redis-socketio-data:
- sites:
- driver_opts:
- type: "${SITE_VOLUME_TYPE}"
- o: "${SITE_VOLUME_OPTS}"
- device: "${SITE_VOLUME_DEV}"
-
-networks:
- bench-network:
\ No newline at end of file
diff --git a/apps/dokploy/templates/erpnext/index.ts b/apps/dokploy/templates/erpnext/index.ts
deleted file mode 100644
index 5b7543b9..00000000
--- a/apps/dokploy/templates/erpnext/index.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const dbRootPassword = generatePassword(32);
- const adminPassword = generatePassword(32);
- const mainDomain = generateRandomDomain(schema);
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 8080,
- serviceName: "frontend",
- },
- ];
-
- const envs = [
- `SITE_NAME=${mainDomain}`,
- `ADMIN_PASSWORD=${adminPassword}`,
- `DB_ROOT_PASSWORD=${dbRootPassword}`,
- "MIGRATE=1",
- "ENABLE_DB=1",
- "DB_HOST=db",
- "CREATE_SITE=1",
- "CONFIGURE=1",
- "REGENERATE_APPS_TXT=1",
- "INSTALL_APP_ARGS=--install-app erpnext",
- "IMAGE_NAME=docker.io/frappe/erpnext",
- "VERSION=version-15",
- "FRAPPE_SITE_NAME_HEADER=",
- ];
-
- return { envs, domains };
-}
diff --git a/apps/dokploy/templates/evolutionapi/docker-compose.yml b/apps/dokploy/templates/evolutionapi/docker-compose.yml
deleted file mode 100644
index d4803de1..00000000
--- a/apps/dokploy/templates/evolutionapi/docker-compose.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-services:
- evolution-api:
- image: atendai/evolution-api:v2.1.2
- restart: always
- volumes:
- - evolution-instances:/evolution/instances
-
- environment:
- - SERVER_URL=${SERVER_URL}
- - AUTHENTICATION_TYPE=${AUTHENTICATION_TYPE}
- - AUTHENTICATION_API_KEY=${AUTHENTICATION_API_KEY}
- - AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=${AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES}
- - LANGUAGE=${LANGUAGE}
- - CONFIG_SESSION_PHONE_CLIENT=${CONFIG_SESSION_PHONE_CLIENT}
- - CONFIG_SESSION_PHONE_NAME=${CONFIG_SESSION_PHONE_NAME}
- - TELEMETRY=${TELEMETRY}
- - TELEMETRY_URL=${TELEMETRY_URL}
- - DATABASE_ENABLED=${DATABASE_ENABLED}
- - DATABASE_PROVIDER=${DATABASE_PROVIDER}
- - DATABASE_CONNECTION_URI=${DATABASE_CONNECTION_URI}
- - DATABASE_SAVE_DATA_INSTANCE=${DATABASE_SAVE_DATA_INSTANCE}
- - DATABASE_SAVE_DATA_NEW_MESSAGE=${DATABASE_SAVE_DATA_NEW_MESSAGE}
- - DATABASE_SAVE_MESSAGE_UPDATE=${DATABASE_SAVE_MESSAGE_UPDATE}
- - DATABASE_SAVE_DATA_CONTACTS=${DATABASE_SAVE_DATA_CONTACTS}
- - DATABASE_SAVE_DATA_CHATS=${DATABASE_SAVE_DATA_CHATS}
- - DATABASE_SAVE_DATA_LABELS=${DATABASE_SAVE_DATA_LABELS}
- - DATABASE_SAVE_DATA_HISTORIC=${DATABASE_SAVE_DATA_HISTORIC}
- - CACHE_REDIS_ENABLED=${CACHE_REDIS_ENABLED}
- - CACHE_REDIS_URI=${CACHE_REDIS_URI}
- - CACHE_REDIS_PREFIX_KEY=${CACHE_REDIS_PREFIX_KEY}
- - CACHE_REDIS_SAVE_INSTANCES=${CACHE_REDIS_SAVE_INSTANCES}
-
- evolution-postgres:
- image: postgres:16-alpine
- restart: always
- volumes:
- - evolution-postgres-data:/var/lib/postgresql/data
-
- environment:
- - POSTGRES_DB=${POSTGRES_DATABASE}
- - POSTGRES_USER=${POSTGRES_USERNAME}
- - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
-
- evolution-redis:
- image: redis:alpine
- restart: always
- volumes:
- - evolution-redis-data:/data
-
-
-networks:
- dokploy-network:
- external: true
-
-volumes:
- evolution-instances:
- evolution-postgres-data:
- evolution-redis-data:
\ No newline at end of file
diff --git a/apps/dokploy/templates/evolutionapi/index.ts b/apps/dokploy/templates/evolutionapi/index.ts
deleted file mode 100644
index 6ca7a3b6..00000000
--- a/apps/dokploy/templates/evolutionapi/index.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateBase64,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
- const apiKey = generateBase64(64);
- const postgresPassword = generatePassword();
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 8080,
- serviceName: "evolution-api",
- },
- ];
-
- const envs = [
- `SERVER_URL=https://${mainDomain}`,
- "AUTHENTICATION_TYPE=apikey",
- `AUTHENTICATION_API_KEY=${apiKey}`,
- "AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true",
-
- "LANGUAGE=en",
- "CONFIG_SESSION_PHONE_CLIENT=Evolution API",
- "CONFIG_SESSION_PHONE_NAME=Chrome",
- "TELEMETRY=false",
- "TELEMETRY_URL=",
-
- "POSTGRES_DATABASE=evolution",
- "POSTGRES_USERNAME=postgresql",
- `POSTGRES_PASSWORD=${postgresPassword}`,
- "DATABASE_ENABLED=true",
- "DATABASE_PROVIDER=postgresql",
- `DATABASE_CONNECTION_URI=postgres://postgresql:${postgresPassword}@evolution-postgres:5432/evolution`,
- "DATABASE_SAVE_DATA_INSTANCE=true",
- "DATABASE_SAVE_DATA_NEW_MESSAGE=true",
- "DATABASE_SAVE_MESSAGE_UPDATE=true",
- "DATABASE_SAVE_DATA_CONTACTS=true",
- "DATABASE_SAVE_DATA_CHATS=true",
- "DATABASE_SAVE_DATA_LABELS=true",
- "DATABASE_SAVE_DATA_HISTORIC=true",
-
- "CACHE_REDIS_ENABLED=true",
- "CACHE_REDIS_URI=redis://evolution-redis:6379",
- "CACHE_REDIS_PREFIX_KEY=evolution",
- "CACHE_REDIS_SAVE_INSTANCES=true",
- ];
-
- return {
- domains,
- envs,
- };
-}
diff --git a/apps/dokploy/templates/excalidraw/docker-compose.yml b/apps/dokploy/templates/excalidraw/docker-compose.yml
index 3cf2fb1d..8743434b 100644
--- a/apps/dokploy/templates/excalidraw/docker-compose.yml
+++ b/apps/dokploy/templates/excalidraw/docker-compose.yml
@@ -2,5 +2,6 @@ version: "3.8"
services:
excalidraw:
-
+ networks:
+ - dokploy-network
image: excalidraw/excalidraw:latest
diff --git a/apps/dokploy/templates/excalidraw/index.ts b/apps/dokploy/templates/excalidraw/index.ts
index 7f73f395..13a43c44 100644
--- a/apps/dokploy/templates/excalidraw/index.ts
+++ b/apps/dokploy/templates/excalidraw/index.ts
@@ -2,6 +2,7 @@ import {
type DomainSchema,
type Schema,
type Template,
+ generateHash,
generateRandomDomain,
} from "../utils";
diff --git a/apps/dokploy/templates/formbricks/docker-compose.yml b/apps/dokploy/templates/formbricks/docker-compose.yml
deleted file mode 100644
index ad1dcbcf..00000000
--- a/apps/dokploy/templates/formbricks/docker-compose.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-x-environment: &environment
- environment:
- WEBAPP_URL: ${WEBAPP_URL}
- NEXTAUTH_URL: ${NEXTAUTH_URL}
- DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/formbricks?schema=public"
- NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
- ENCRYPTION_KEY: ${ENCRYPTION_KEY}
- CRON_SECRET: ${CRON_SECRET}
- EMAIL_VERIFICATION_DISABLED: 1
- PASSWORD_RESET_DISABLED: 1
- S3_FORCE_PATH_STYLE: 0
-
-services:
- postgres:
- restart: always
- image: pgvector/pgvector:pg17
- volumes:
- - postgres:/var/lib/postgresql/data
- environment:
- - POSTGRES_PASSWORD=postgres
-
-
- formbricks:
- restart: always
- image: ghcr.io/formbricks/formbricks:v3.1.3
- depends_on:
- - postgres
- ports:
- - 3000
- volumes:
- - ../files/uploads:/home/nextjs/apps/web/uploads/
- <<: *environment
-
-volumes:
- postgres:
- driver: local
- uploads:
diff --git a/apps/dokploy/templates/formbricks/index.ts b/apps/dokploy/templates/formbricks/index.ts
deleted file mode 100644
index fc179f49..00000000
--- a/apps/dokploy/templates/formbricks/index.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateBase64,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
- const secretBase = generateBase64(64);
- const encryptionKey = generateBase64(48);
- const cronSecret = generateBase64(32);
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 3000,
- serviceName: "formbricks",
- },
- ];
-
- const envs = [
- `WEBAPP_URL=http://${mainDomain}`,
- `NEXTAUTH_URL=http://${mainDomain}`,
- `NEXTAUTH_SECRET=${secretBase}`,
- `ENCRYPTION_KEY=${encryptionKey}`,
- `CRON_SECRET=${cronSecret}`,
- ];
-
- const mounts: Template["mounts"] = [];
-
- return {
- envs,
- mounts,
- domains,
- };
-}
diff --git a/apps/dokploy/templates/frappe-hr/docker-compose.yml b/apps/dokploy/templates/frappe-hr/docker-compose.yml
deleted file mode 100644
index a7ce9b26..00000000
--- a/apps/dokploy/templates/frappe-hr/docker-compose.yml
+++ /dev/null
@@ -1,354 +0,0 @@
-x-custom-image: &custom_image
- image: ${IMAGE_NAME:-ghcr.io/frappe/hrms}:${VERSION:-version-15}
- pull_policy: ${PULL_POLICY:-always}
- deploy:
- restart_policy:
- condition: always
-
-services:
- backend:
- <<: *custom_image
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - '0.0.0.0:8000'
- interval: 2s
- timeout: 10s
- retries: 30
-
- frontend:
- <<: *custom_image
- command:
- - nginx-entrypoint.sh
- depends_on:
- backend:
- condition: service_started
- required: true
- websocket:
- condition: service_started
- required: true
- environment:
- BACKEND: backend:8000
- FRAPPE_SITE_NAME_HEADER: ${FRAPPE_SITE_NAME_HEADER:-$$host}
- SOCKETIO: websocket:9000
- UPSTREAM_REAL_IP_ADDRESS: 127.0.0.1
- UPSTREAM_REAL_IP_HEADER: X-Forwarded-For
- UPSTREAM_REAL_IP_RECURSIVE: "off"
- volumes:
- - sites:/home/frappe/frappe-bench/sites
-
- networks:
- - bench-network
-
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - '0.0.0.0:8080'
- interval: 2s
- timeout: 30s
- retries: 30
-
- queue-default:
- <<: *custom_image
- command:
- - bench
- - worker
- - --queue
- - default
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - 'redis-queue:6379'
- interval: 2s
- timeout: 10s
- retries: 30
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
-
- queue-long:
- <<: *custom_image
- command:
- - bench
- - worker
- - --queue
- - long
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - 'redis-queue:6379'
- interval: 2s
- timeout: 10s
- retries: 30
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
-
- queue-short:
- <<: *custom_image
- command:
- - bench
- - worker
- - --queue
- - short
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - 'redis-queue:6379'
- interval: 2s
- timeout: 10s
- retries: 30
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
-
- scheduler:
- <<: *custom_image
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - 'redis-queue:6379'
- interval: 2s
- timeout: 10s
- retries: 30
- command:
- - bench
- - schedule
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
-
- websocket:
- <<: *custom_image
- healthcheck:
- test:
- - CMD
- - wait-for-it
- - '0.0.0.0:9000'
- interval: 2s
- timeout: 10s
- retries: 30
- command:
- - node
- - /home/frappe/frappe-bench/apps/frappe/socketio.js
- depends_on:
- configurator:
- condition: service_completed_successfully
- required: true
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
-
- configurator:
- <<: *custom_image
- deploy:
- mode: replicated
- replicas: ${CONFIGURE:-0}
- restart_policy:
- condition: none
- entrypoint: ["bash", "-c"]
- command:
- - >
- [[ $${REGENERATE_APPS_TXT} == "1" ]] && ls -1 apps > sites/apps.txt;
- [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && exit 0;
- bench set-config -g db_host $$DB_HOST;
- bench set-config -gp db_port $$DB_PORT;
- bench set-config -g redis_cache "redis://$$REDIS_CACHE";
- bench set-config -g redis_queue "redis://$$REDIS_QUEUE";
- bench set-config -g redis_socketio "redis://$$REDIS_QUEUE";
- bench set-config -gp socketio_port $$SOCKETIO_PORT;
- environment:
- DB_HOST: "${DB_HOST:-db}"
- DB_PORT: "3306"
- REDIS_CACHE: redis-cache:6379
- REDIS_QUEUE: redis-queue:6379
- SOCKETIO_PORT: "9000"
- REGENERATE_APPS_TXT: "${REGENERATE_APPS_TXT:-0}"
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
-
- create-site:
- <<: *custom_image
- deploy:
- mode: replicated
- replicas: ${CREATE_SITE:-0}
- restart_policy:
- condition: none
- entrypoint: ["bash", "-c"]
- command:
- - >
- wait-for-it -t 120 $$DB_HOST:$$DB_PORT;
- wait-for-it -t 120 redis-cache:6379;
- wait-for-it -t 120 redis-queue:6379;
- export start=`date +%s`;
- until [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".db_host // empty"` ]] && \
- [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_cache // empty"` ]] && \
- [[ -n `grep -hs ^ sites/common_site_config.json | jq -r ".redis_queue // empty"` ]];
- do
- echo "Waiting for sites/common_site_config.json to be created";
- sleep 5;
- if (( `date +%s`-start > 120 )); then
- echo "could not find sites/common_site_config.json with required keys";
- exit 1
- fi
- done;
- echo "sites/common_site_config.json found";
- [[ -d "sites/${SITE_NAME}" ]] && echo "${SITE_NAME} already exists" && exit 0;
- bench new-site --mariadb-user-host-login-scope='%' --admin-password=$${ADMIN_PASSWORD} --db-root-username=root --db-root-password=$${DB_ROOT_PASSWORD} $${INSTALL_APP_ARGS} $${SITE_NAME};
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- environment:
- SITE_NAME: ${SITE_NAME}
- ADMIN_PASSWORD: ${ADMIN_PASSWORD}
- DB_HOST: ${DB_HOST:-db}
- DB_PORT: "${DB_PORT:-3306}"
- DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
- INSTALL_APP_ARGS: ${INSTALL_APP_ARGS}
- networks:
- - bench-network
-
- migration:
- <<: *custom_image
- deploy:
- mode: replicated
- replicas: ${MIGRATE:-0}
- restart_policy:
- condition: none
- entrypoint: ["bash", "-c"]
- command:
- - >
- curl -f http://${SITE_NAME}:8080/api/method/ping || echo "Site busy" && exit 0;
- bench --site all set-config -p maintenance_mode 1;
- bench --site all set-config -p pause_scheduler 1;
- bench --site all migrate;
- bench --site all set-config -p maintenance_mode 0;
- bench --site all set-config -p pause_scheduler 0;
- volumes:
- - sites:/home/frappe/frappe-bench/sites
- networks:
- - bench-network
-
- db:
- image: mariadb:10.6
- deploy:
- mode: replicated
- replicas: ${ENABLE_DB:-0}
- restart_policy:
- condition: always
- healthcheck:
- test: mysqladmin ping -h localhost --password=${DB_ROOT_PASSWORD}
- interval: 1s
- retries: 20
- command:
- - --character-set-server=utf8mb4
- - --collation-server=utf8mb4_unicode_ci
- - --skip-character-set-client-handshake
- - --skip-innodb-read-only-compressed
- environment:
- - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- - MARIADB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- volumes:
- - db-data:/var/lib/mysql
- networks:
- - bench-network
-
- redis-cache:
- deploy:
- restart_policy:
- condition: always
- image: redis:6.2-alpine
- volumes:
- - redis-cache-data:/data
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - redis-cli
- - ping
- interval: 5s
- timeout: 5s
- retries: 3
-
- redis-queue:
- deploy:
- restart_policy:
- condition: always
- image: redis:6.2-alpine
- volumes:
- - redis-queue-data:/data
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - redis-cli
- - ping
- interval: 5s
- timeout: 5s
- retries: 3
-
- redis-socketio:
- deploy:
- restart_policy:
- condition: always
- image: redis:6.2-alpine
- volumes:
- - redis-socketio-data:/data
- networks:
- - bench-network
- healthcheck:
- test:
- - CMD
- - redis-cli
- - ping
- interval: 5s
- timeout: 5s
- retries: 3
-
-volumes:
- db-data:
- redis-cache-data:
- redis-queue-data:
- redis-socketio-data:
- sites:
- driver_opts:
- type: "${SITE_VOLUME_TYPE}"
- o: "${SITE_VOLUME_OPTS}"
- device: "${SITE_VOLUME_DEV}"
-
-networks:
- bench-network:
\ No newline at end of file
diff --git a/apps/dokploy/templates/frappe-hr/index.ts b/apps/dokploy/templates/frappe-hr/index.ts
deleted file mode 100644
index 1e6b9474..00000000
--- a/apps/dokploy/templates/frappe-hr/index.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const dbRootPassword = generatePassword(32);
- const adminPassword = generatePassword(32);
- const mainDomain = generateRandomDomain(schema);
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 8080,
- serviceName: "frontend",
- },
- ];
-
- const envs = [
- `SITE_NAME=${mainDomain}`,
- `ADMIN_PASSWORD=${adminPassword}`,
- `DB_ROOT_PASSWORD=${dbRootPassword}`,
- "MIGRATE=1",
- "ENABLE_DB=1",
- "DB_HOST=db",
- "CREATE_SITE=1",
- "CONFIGURE=1",
- "REGENERATE_APPS_TXT=1",
- "INSTALL_APP_ARGS=--install-app hrms",
- "IMAGE_NAME=ghcr.io/frappe/hrms",
- "VERSION=version-15",
- "FRAPPE_SITE_NAME_HEADER=",
- ];
-
- return { envs, domains };
-}
diff --git a/apps/dokploy/templates/ghost/docker-compose.yml b/apps/dokploy/templates/ghost/docker-compose.yml
index 33c47f7f..288c59e5 100644
--- a/apps/dokploy/templates/ghost/docker-compose.yml
+++ b/apps/dokploy/templates/ghost/docker-compose.yml
@@ -17,7 +17,8 @@ services:
db:
image: mysql:8.0
restart: always
-
+ networks:
+ - dokploy-network
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
diff --git a/apps/dokploy/templates/ghost/index.ts b/apps/dokploy/templates/ghost/index.ts
index 052b7c6b..1a88c362 100644
--- a/apps/dokploy/templates/ghost/index.ts
+++ b/apps/dokploy/templates/ghost/index.ts
@@ -2,6 +2,7 @@ import {
type DomainSchema,
type Schema,
type Template,
+ generateHash,
generateRandomDomain,
} from "../utils";
diff --git a/apps/dokploy/templates/gitea/docker-compose.yml b/apps/dokploy/templates/gitea/docker-compose.yml
index 5127224c..72e0754e 100644
--- a/apps/dokploy/templates/gitea/docker-compose.yml
+++ b/apps/dokploy/templates/gitea/docker-compose.yml
@@ -11,7 +11,8 @@ services:
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=gitea
restart: always
-
+ networks:
+ - dokploy-network
volumes:
- gitea_server:/data
- /etc/timezone:/etc/timezone:ro
@@ -26,7 +27,8 @@ services:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=gitea
- POSTGRES_DB=gitea
-
+ networks:
+ - dokploy-network
volumes:
- gitea_db:/var/lib/postgresql/data
diff --git a/apps/dokploy/templates/glance/docker-compose.yml b/apps/dokploy/templates/glance/docker-compose.yml
deleted file mode 100644
index ace8bc94..00000000
--- a/apps/dokploy/templates/glance/docker-compose.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-services:
- glance:
- image: glanceapp/glance
- volumes:
- - ../files/app/config/:/app/config
- - ../files/app/assets:/app/assets
- # Optionally, also mount docker socket if you want to use the docker containers widget
- # - /var/run/docker.sock:/var/run/docker.sock:ro
- ports:
- - 8080
- env_file: .env
\ No newline at end of file
diff --git a/apps/dokploy/templates/glance/index.ts b/apps/dokploy/templates/glance/index.ts
deleted file mode 100644
index a0ab1b67..00000000
--- a/apps/dokploy/templates/glance/index.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 8080,
- serviceName: "glance",
- },
- ];
-
- const mounts: Template["mounts"] = [
- {
- filePath: "/app/config/glance.yml",
- content: `
-branding:
- hide-footer: true
- logo-text: P
-
-pages:
- - name: Home
- columns:
- - size: small
- widgets:
- - type: calendar
-
- - type: releases
- show-source-icon: true
- repositories:
- - Dokploy/dokploy
- - n8n-io/n8n
- - Budibase/budibase
- - home-assistant/core
- - tidbyt/pixlet
-
- - type: twitch-channels
- channels:
- - nmplol
- - extraemily
- - qtcinderella
- - ludwig
- - timthetatman
- - mizkif
-
- - size: full
- widgets:
- - type: hacker-news
-
- - type: videos
- style: grid-cards
- channels:
- - UC3GzdWYwUYI1ACxuP9Nm-eg
- - UCGbg3DjQdcqWwqOLHpYHXIg
- - UC24RSoLcjiNZbQcT54j5l7Q
- limit: 3
-
- - type: rss
- limit: 10
- collapse-after: 3
- cache: 3h
- feeds:
- - url: https://daringfireball.net/feeds/main
- title: Daring Fireball
-
- - size: small
- widgets:
- - type: weather
- location: Gansevoort, New York, United States
- show-area-name: false
- units: imperial
- hour-format: 12h
-
- - type: markets
- markets:
- - symbol: SPY
- name: S&P 500
- - symbol: VOO
- name: Vanguard
- - symbol: BTC-USD
- name: Bitcoin
- - symbol: ETH-USD
- name: Etherium
- - symbol: NVDA
- name: NVIDIA
- - symbol: AAPL
- name: Apple
- - symbol: MSFT
- name: Microsoft
- - symbol: GOOGL
- name: Google
- - symbol: AMD
- name: AMD
- - symbol: TSLA
- name: Tesla`,
- },
- ];
-
- return {
- domains,
- mounts,
- };
-}
diff --git a/apps/dokploy/templates/glitchtip/docker-compose.yml b/apps/dokploy/templates/glitchtip/docker-compose.yml
index f47742f0..e45c7662 100644
--- a/apps/dokploy/templates/glitchtip/docker-compose.yml
+++ b/apps/dokploy/templates/glitchtip/docker-compose.yml
@@ -20,11 +20,13 @@ services:
restart: unless-stopped
volumes:
- pg-data:/var/lib/postgresql/data
-
+ networks:
+ - dokploy-network
redis:
image: redis
restart: unless-stopped
-
+ networks:
+ - dokploy-network
web:
image: glitchtip/glitchtip:v4.0
depends_on: *default-depends_on
@@ -42,13 +44,15 @@ services:
restart: unless-stopped
volumes:
- uploads:/code/uploads
-
+ networks:
+ - dokploy-network
migrate:
image: glitchtip/glitchtip:v4.0
depends_on: *default-depends_on
command: "./manage.py migrate"
environment: *default-environment
-
+ networks:
+ - dokploy-network
volumes:
pg-data:
diff --git a/apps/dokploy/templates/glpi/docker-compose.yml b/apps/dokploy/templates/glpi/docker-compose.yml
index fa732fa3..f15cdafe 100644
--- a/apps/dokploy/templates/glpi/docker-compose.yml
+++ b/apps/dokploy/templates/glpi/docker-compose.yml
@@ -4,7 +4,8 @@ services:
restart: always
volumes:
- glpi-mysql-data:/var/lib/mysql
-
+ networks:
+ - dokploy-network
glpi-web:
image: elestio/glpi:10.0.16
@@ -15,7 +16,8 @@ services:
- glpi-www-data:/var/www/html/glpi
environment:
- TIMEZONE=Europe/Brussels
-
+ networks:
+ - dokploy-network
volumes:
glpi-mysql-data:
diff --git a/apps/dokploy/templates/hi-events/docker-compose.yml b/apps/dokploy/templates/hi-events/docker-compose.yml
index cce45fec..0ce5b7e7 100644
--- a/apps/dokploy/templates/hi-events/docker-compose.yml
+++ b/apps/dokploy/templates/hi-events/docker-compose.yml
@@ -28,7 +28,8 @@ services:
postgres:
image: elestio/postgres:16
restart: always
-
+ networks:
+ - dokploy-network
environment:
- POSTGRES_DB
- POSTGRES_USER
diff --git a/apps/dokploy/templates/homarr/docker-compose.yml b/apps/dokploy/templates/homarr/docker-compose.yml
deleted file mode 100644
index 876ea3f6..00000000
--- a/apps/dokploy/templates/homarr/docker-compose.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-services:
- homarr:
- image: ghcr.io/homarr-labs/homarr:latest
- restart: unless-stopped
- volumes:
- # - /var/run/docker.sock:/var/run/docker.sock # Optional, only if you want docker integration
- - ../homarr/appdata:/appdata
- environment:
- - SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
- ports:
- - 7575
diff --git a/apps/dokploy/templates/homarr/index.ts b/apps/dokploy/templates/homarr/index.ts
deleted file mode 100644
index eb5a9f82..00000000
--- a/apps/dokploy/templates/homarr/index.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
- const secretKey = generatePassword(64);
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 7575,
- serviceName: "homarr",
- },
- ];
-
- const envs = [`SECRET_ENCRYPTION_KEY=${secretKey}`];
-
- return {
- domains,
- envs,
- };
-}
diff --git a/apps/dokploy/templates/huly/docker-compose.yml b/apps/dokploy/templates/huly/docker-compose.yml
index 639b10d2..471ee7e9 100644
--- a/apps/dokploy/templates/huly/docker-compose.yml
+++ b/apps/dokploy/templates/huly/docker-compose.yml
@@ -2,7 +2,8 @@ name: ${DOCKER_NAME}
version: "3"
services:
nginx:
-
+ networks:
+ - dokploy-network
image: "nginx:1.21.3"
ports:
- 80
@@ -11,7 +12,8 @@ services:
restart: unless-stopped
mongodb:
-
+ networks:
+ - dokploy-network
image: "mongo:7-jammy"
environment:
- PUID=1000
@@ -21,7 +23,8 @@ services:
restart: unless-stopped
minio:
-
+ networks:
+ - dokploy-network
image: "minio/minio:RELEASE.2024-11-07T00-52-20Z"
command: server /data --address ":9000" --console-address ":9001"
volumes:
@@ -29,7 +32,8 @@ services:
restart: unless-stopped
elastic:
-
+ networks:
+ - dokploy-network
image: "elasticsearch:7.14.2"
command: |
/bin/sh -c "./bin/elasticsearch-plugin list | grep -q ingest-attachment || yes | ./bin/elasticsearch-plugin install --silent ingest-attachment;
@@ -50,7 +54,8 @@ services:
restart: unless-stopped
rekoni:
-
+ networks:
+ - dokploy-network
image: hardcoreeng/rekoni-service:${HULY_VERSION}
environment:
- SECRET=${SECRET}
@@ -61,7 +66,8 @@ services:
restart: unless-stopped
transactor:
-
+ networks:
+ - dokploy-network
image: hardcoreeng/transactor:${HULY_VERSION}
environment:
- SERVER_PORT=3333
@@ -78,7 +84,8 @@ services:
restart: unless-stopped
collaborator:
-
+ networks:
+ - dokploy-network
image: hardcoreeng/collaborator:${HULY_VERSION}
environment:
- COLLABORATOR_PORT=3078
@@ -90,7 +97,8 @@ services:
restart: unless-stopped
account:
-
+ networks:
+ - dokploy-network
image: hardcoreeng/account:${HULY_VERSION}
environment:
- SERVER_PORT=3000
@@ -107,7 +115,8 @@ services:
restart: unless-stopped
workspace:
-
+ networks:
+ - dokploy-network
image: hardcoreeng/workspace:${HULY_VERSION}
environment:
- SERVER_SECRET=${SECRET}
@@ -121,7 +130,8 @@ services:
restart: unless-stopped
front:
-
+ networks:
+ - dokploy-network
image: hardcoreeng/front:${HULY_VERSION}
environment:
- SERVER_PORT=8080
@@ -146,7 +156,8 @@ services:
restart: unless-stopped
fulltext:
-
+ networks:
+ - dokploy-network
image: hardcoreeng/fulltext:${HULY_VERSION}
environment:
- SERVER_SECRET=${SECRET}
@@ -160,7 +171,8 @@ services:
restart: unless-stopped
stats:
-
+ networks:
+ - dokploy-network
image: hardcoreeng/stats:${HULY_VERSION}
environment:
- PORT=4900
diff --git a/apps/dokploy/templates/immich/docker-compose.yml b/apps/dokploy/templates/immich/docker-compose.yml
index 743f70ac..2a9fb00b 100644
--- a/apps/dokploy/templates/immich/docker-compose.yml
+++ b/apps/dokploy/templates/immich/docker-compose.yml
@@ -3,7 +3,8 @@ version: "3.9"
services:
immich-server:
image: ghcr.io/immich-app/immich-server:v1.121.0
-
+ networks:
+ - dokploy-network
volumes:
- immich-library:/usr/src/app/upload
- /etc/localtime:/etc/localtime:ro
@@ -37,7 +38,8 @@ services:
immich-machine-learning:
image: ghcr.io/immich-app/immich-machine-learning:v1.121.0
-
+ networks:
+ - dokploy-network
volumes:
- immich-model-cache:/cache
environment:
@@ -53,7 +55,8 @@ services:
immich-redis:
image: redis:6.2-alpine
-
+ networks:
+ - dokploy-network
volumes:
- immich-redis-data:/data
healthcheck:
@@ -65,7 +68,8 @@ services:
immich-database:
image: tensorchord/pgvecto-rs:pg14-v0.2.0
-
+ networks:
+ - dokploy-network
volumes:
- immich-postgres:/var/lib/postgresql/data
environment:
diff --git a/apps/dokploy/templates/immich/index.ts b/apps/dokploy/templates/immich/index.ts
index 4beca87d..b1b11afb 100644
--- a/apps/dokploy/templates/immich/index.ts
+++ b/apps/dokploy/templates/immich/index.ts
@@ -11,7 +11,7 @@ export function generate(schema: Schema): Template {
const mainDomain = generateRandomDomain(schema);
const dbPassword = generatePassword();
const dbUser = "immich";
- const _appSecret = generateBase64(32);
+ const appSecret = generateBase64(32);
const domains: DomainSchema[] = [
{
diff --git a/apps/dokploy/templates/infisical/docker-compose.yml b/apps/dokploy/templates/infisical/docker-compose.yml
index 7566c898..3baca926 100644
--- a/apps/dokploy/templates/infisical/docker-compose.yml
+++ b/apps/dokploy/templates/infisical/docker-compose.yml
@@ -19,7 +19,8 @@ services:
- SMTP_SECURE=true
command: npm run migration:latest
pull_policy: always
-
+ networks:
+ - dokploy-network
backend:
restart: unless-stopped
@@ -45,7 +46,8 @@ services:
- SMTP_USERNAME
- SMTP_PASSWORD
- SMTP_SECURE=true
-
+ networks:
+ - dokploy-network
redis:
image: redis:7.4.1
@@ -53,7 +55,8 @@ services:
restart: always
environment:
- ALLOW_EMPTY_PASSWORD=yes
-
+ networks:
+ - dokploy-network
volumes:
- redis_infisical_data:/data
@@ -66,7 +69,8 @@ services:
- POSTGRES_DB
volumes:
- pg_infisical_data:/var/lib/postgresql/data
-
+ networks:
+ - dokploy-network
healthcheck:
test: "pg_isready --username=${POSTGRES_USER} && psql --username=${POSTGRES_USER} --list"
interval: 5s
diff --git a/apps/dokploy/templates/invoiceshelf/docker-compose.yml b/apps/dokploy/templates/invoiceshelf/docker-compose.yml
index ef47f1c0..5afdd152 100644
--- a/apps/dokploy/templates/invoiceshelf/docker-compose.yml
+++ b/apps/dokploy/templates/invoiceshelf/docker-compose.yml
@@ -3,7 +3,8 @@ version: "3.8"
services:
invoiceshelf-postgres:
image: postgres:15
-
+ networks:
+ - dokploy-network
volumes:
- invoiceshelf-postgres-data:/var/lib/postgresql/data
environment:
@@ -18,7 +19,8 @@ services:
invoiceshelf-app:
image: invoiceshelf/invoiceshelf:latest
-
+ networks:
+ - dokploy-network
volumes:
- invoiceshelf-app-data:/data
- invoiceshelf-app-conf:/conf
diff --git a/apps/dokploy/templates/kimai/docker-compose.yml b/apps/dokploy/templates/kimai/docker-compose.yml
index 253ecb00..6a04b3b9 100644
--- a/apps/dokploy/templates/kimai/docker-compose.yml
+++ b/apps/dokploy/templates/kimai/docker-compose.yml
@@ -16,7 +16,8 @@ services:
depends_on:
db:
condition: service_healthy
-
+ networks:
+ - dokploy-network
db:
image: mariadb:10.11
restart: unless-stopped
@@ -38,7 +39,8 @@ services:
timeout: 5s
retries: 5
start_period: 30s
-
+ networks:
+ - dokploy-network
networks:
dokploy-network:
diff --git a/apps/dokploy/templates/langflow/docker-compose.yml b/apps/dokploy/templates/langflow/docker-compose.yml
index a9628286..75bb73dd 100644
--- a/apps/dokploy/templates/langflow/docker-compose.yml
+++ b/apps/dokploy/templates/langflow/docker-compose.yml
@@ -12,7 +12,8 @@ services:
# This variable defines where the logs, file storage, monitor data and secret keys are stored.
volumes:
- langflow-data:/app/langflow
-
+ networks:
+ - dokploy-network
postgres-langflow:
image: postgres:16
@@ -24,7 +25,8 @@ services:
- 5432
volumes:
- langflow-postgres:/var/lib/postgresql/data
-
+ networks:
+ - dokploy-network
volumes:
langflow-postgres:
diff --git a/apps/dokploy/templates/linkwarden/docker-compose.yml b/apps/dokploy/templates/linkwarden/docker-compose.yml
deleted file mode 100644
index 05ffb8a0..00000000
--- a/apps/dokploy/templates/linkwarden/docker-compose.yml
+++ /dev/null
@@ -1,40 +0,0 @@
-services:
- linkwarden:
- environment:
- - NEXTAUTH_SECRET
- - NEXTAUTH_URL
- - DATABASE_URL=postgresql://linkwarden:${POSTGRES_PASSWORD}@postgres:5432/linkwarden
- restart: unless-stopped
- image: ghcr.io/linkwarden/linkwarden:v2.9.3
- ports:
- - 3000
- volumes:
- - linkwarden-data:/data/data
- depends_on:
- - postgres
- healthcheck:
- test: curl --fail http://localhost:3000 || exit 1
- interval: 60s
- retries: 2
- start_period: 60s
- timeout: 15s
-
- postgres:
- image: postgres:17-alpine
- restart: unless-stopped
- user: postgres
- environment:
- POSTGRES_USER: linkwarden
- POSTGRES_DB: linkwarden
- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
- volumes:
- - postgres-data:/var/lib/postgresql/data
- healthcheck:
- test: ["CMD-SHELL", "pg_isready"]
- interval: 10s
- timeout: 5s
- retries: 5
-
-volumes:
- linkwarden-data:
- postgres-data:
diff --git a/apps/dokploy/templates/linkwarden/index.ts b/apps/dokploy/templates/linkwarden/index.ts
deleted file mode 100644
index 86025035..00000000
--- a/apps/dokploy/templates/linkwarden/index.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateBase64,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
- const postgresPassword = generatePassword();
- const nextSecret = generateBase64(32);
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 3000,
- serviceName: "linkwarden",
- },
- ];
-
- const envs = [
- `POSTGRES_PASSWORD=${postgresPassword}`,
- `NEXTAUTH_SECRET=${nextSecret}`,
- `NEXTAUTH_URL=http://${mainDomain}/api/v1/auth`,
- ];
-
- return {
- domains,
- envs,
- };
-}
diff --git a/apps/dokploy/templates/listmonk/docker-compose.yml b/apps/dokploy/templates/listmonk/docker-compose.yml
index d9da8b50..725d0a09 100644
--- a/apps/dokploy/templates/listmonk/docker-compose.yml
+++ b/apps/dokploy/templates/listmonk/docker-compose.yml
@@ -1,9 +1,10 @@
services:
db:
- image: postgres:17-alpine
+ image: postgres:13
ports:
- 5432
-
+ networks:
+ - dokploy-network
environment:
- POSTGRES_PASSWORD=listmonk
- POSTGRES_USER=listmonk
@@ -18,8 +19,9 @@ services:
- listmonk-data:/var/lib/postgresql/data
setup:
- image: listmonk/listmonk:v4.1.0
-
+ image: listmonk/listmonk:v3.0.0
+ networks:
+ - dokploy-network
volumes:
- ../files/config.toml:/listmonk/config.toml
depends_on:
@@ -33,7 +35,7 @@ services:
app:
restart: unless-stopped
- image: listmonk/listmonk:v4.1.0
+ image: listmonk/listmonk:v3.0.0
environment:
- TZ=Etc/UTC
depends_on:
@@ -41,9 +43,7 @@ services:
- setup
volumes:
- ../files/config.toml:/listmonk/config.toml
- - listmonk-uploads:/listmonk/uploads
volumes:
- listmonk-uploads:
listmonk-data:
driver: local
diff --git a/apps/dokploy/templates/listmonk/index.ts b/apps/dokploy/templates/listmonk/index.ts
index 2a25efca..725659ca 100644
--- a/apps/dokploy/templates/listmonk/index.ts
+++ b/apps/dokploy/templates/listmonk/index.ts
@@ -2,11 +2,13 @@ import {
type DomainSchema,
type Schema,
type Template,
+ generatePassword,
generateRandomDomain,
} from "../utils";
export function generate(schema: Schema): Template {
const randomDomain = generateRandomDomain(schema);
+ const adminPassword = generatePassword(32);
const domains: DomainSchema[] = [
{
@@ -17,7 +19,7 @@ export function generate(schema: Schema): Template {
];
const envs = [
- "# visit the page to setup your super admin user",
+ `# login with admin:${adminPassword}`,
"# check config.toml in Advanced / Volumes for more options",
];
@@ -27,6 +29,9 @@ export function generate(schema: Schema): Template {
content: `[app]
address = "0.0.0.0:9000"
+admin_username = "admin"
+admin_password = "${adminPassword}"
+
[db]
host = "db"
port = 5432
diff --git a/apps/dokploy/templates/logto/docker-compose.yml b/apps/dokploy/templates/logto/docker-compose.yml
index 6f2b920a..e1f7c46a 100644
--- a/apps/dokploy/templates/logto/docker-compose.yml
+++ b/apps/dokploy/templates/logto/docker-compose.yml
@@ -8,7 +8,8 @@ services:
ports:
- 3001
- 3002
-
+ networks:
+ - dokploy-network
environment:
TRUST_PROXY_HEADER: 1
DB_URL: postgres://logto:${LOGTO_POSTGRES_PASSWORD}@postgres:5432/logto
@@ -19,7 +20,8 @@ services:
postgres:
image: postgres:17-alpine
user: postgres
-
+ networks:
+ - dokploy-network
environment:
POSTGRES_USER: logto
POSTGRES_PASSWORD: ${LOGTO_POSTGRES_PASSWORD}
diff --git a/apps/dokploy/templates/mailpit/docker-compose.yml b/apps/dokploy/templates/mailpit/docker-compose.yml
deleted file mode 100644
index d0dbdb8e..00000000
--- a/apps/dokploy/templates/mailpit/docker-compose.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-services:
- mailpit:
- image: axllent/mailpit:v1.22.3
- restart: unless-stopped
- ports:
- - '1025:1025'
- volumes:
- - 'mailpit-data:/data'
- environment:
- - MP_SMTP_AUTH_ALLOW_INSECURE=true
- - MP_MAX_MESSAGES=5000
- - MP_DATABASE=/data/mailpit.db
- - MP_UI_AUTH=${MP_UI_AUTH}
- - MP_SMTP_AUTH=${MP_SMTP_AUTH}
- healthcheck:
- test:
- - CMD
- - /mailpit
- - readyz
- interval: 5s
- timeout: 20s
- retries: 10
-
-volumes:
- mailpit-data:
\ No newline at end of file
diff --git a/apps/dokploy/templates/mailpit/index.ts b/apps/dokploy/templates/mailpit/index.ts
deleted file mode 100644
index 25f18f7e..00000000
--- a/apps/dokploy/templates/mailpit/index.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateBase64,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const domains: DomainSchema[] = [
- {
- host: generateRandomDomain(schema),
- port: 8025,
- serviceName: "mailpit",
- },
- ];
-
- const defaultPassword = generatePassword();
-
- const envs = [
- "# Uncomment below if you want basic auth on UI and SMTP",
- `#MP_UI_AUTH=mailpit:${defaultPassword}`,
- `#MP_SMTP_AUTH=mailpit:${defaultPassword}`,
- ];
-
- return {
- domains,
- envs,
- };
-}
diff --git a/apps/dokploy/templates/maybe/docker-compose.yml b/apps/dokploy/templates/maybe/docker-compose.yml
deleted file mode 100644
index db529e0a..00000000
--- a/apps/dokploy/templates/maybe/docker-compose.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-services:
- app:
- image: ghcr.io/maybe-finance/maybe:sha-68c570eed8810fd59b5b33cca51bbad5eabb4cb4
- restart: unless-stopped
- volumes:
- - ../files/uploads:/app/uploads
- environment:
- DATABASE_URL: postgresql://maybe:maybe@db:5432/maybe
- SECRET_KEY_BASE: ${SECRET_KEY_BASE}
- SELF_HOSTED: true
- SYNTH_API_KEY: ${SYNTH_API_KEY}
- RAILS_FORCE_SSL: "false"
- RAILS_ASSUME_SSL: "false"
- GOOD_JOB_EXECUTION_MODE: async
- depends_on:
- db:
- condition: service_healthy
-
- db:
- image: postgres:16
- restart: always
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
- interval: 5s
- timeout: 5s
- retries: 5
-
- volumes:
- - db-data:/var/lib/postgresql/data
- environment:
- POSTGRES_DB: maybe
- POSTGRES_USER: maybe
- POSTGRES_PASSWORD: maybe
-
-volumes:
- db-data:
diff --git a/apps/dokploy/templates/maybe/index.ts b/apps/dokploy/templates/maybe/index.ts
deleted file mode 100644
index 5eaf7a81..00000000
--- a/apps/dokploy/templates/maybe/index.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateBase64,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
- const secretKeyBase = generateBase64(64);
- const synthApiKey = generateBase64(32);
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 3000,
- serviceName: "app",
- },
- ];
-
- const envs = [
- `SECRET_KEY_BASE=${secretKeyBase}`,
- "SELF_HOSTED=true",
- `SYNTH_API_KEY=${synthApiKey}`,
- "RAILS_FORCE_SSL=false",
- "RAILS_ASSUME_SSL=false",
- "GOOD_JOB_EXECUTION_MODE=async",
- ];
-
- const mounts: Template["mounts"] = [
- {
- filePath: "./uploads",
- content: "This is where user uploads will be stored",
- },
- ];
-
- return {
- envs,
- mounts,
- domains,
- };
-}
diff --git a/apps/dokploy/templates/metabase/docker-compose.yml b/apps/dokploy/templates/metabase/docker-compose.yml
index 43a03987..4dca4d01 100644
--- a/apps/dokploy/templates/metabase/docker-compose.yml
+++ b/apps/dokploy/templates/metabase/docker-compose.yml
@@ -22,4 +22,5 @@ services:
POSTGRES_USER: metabase
POSTGRES_DB: metabaseappdb
POSTGRES_PASSWORD: mysecretpassword
-
+ networks:
+ - dokploy-network
diff --git a/apps/dokploy/templates/nextcloud-aio/docker-compose.yml b/apps/dokploy/templates/nextcloud-aio/docker-compose.yml
index 1e6d00fe..e8381d2b 100644
--- a/apps/dokploy/templates/nextcloud-aio/docker-compose.yml
+++ b/apps/dokploy/templates/nextcloud-aio/docker-compose.yml
@@ -2,7 +2,8 @@ services:
nextcloud:
image: nextcloud:30.0.2
restart: always
-
+ networks:
+ - dokploy-network
ports:
- 80
volumes:
@@ -18,7 +19,8 @@ services:
nextcloud_db:
image: mariadb
restart: always
-
+ networks:
+ - dokploy-network
volumes:
- nextcloud_db_data:/var/lib/mysql
environment:
diff --git a/apps/dokploy/templates/nocodb/docker-compose.yml b/apps/dokploy/templates/nocodb/docker-compose.yml
index 7c4fd1e9..3d5c9ee7 100644
--- a/apps/dokploy/templates/nocodb/docker-compose.yml
+++ b/apps/dokploy/templates/nocodb/docker-compose.yml
@@ -13,7 +13,8 @@ services:
root_db:
image: postgres:17
restart: always
-
+ networks:
+ - dokploy-network
environment:
POSTGRES_DB: root_db
POSTGRES_PASSWORD: password
diff --git a/apps/dokploy/templates/odoo/docker-compose.yml b/apps/dokploy/templates/odoo/docker-compose.yml
index 7c1c7d3c..80b34f0c 100644
--- a/apps/dokploy/templates/odoo/docker-compose.yml
+++ b/apps/dokploy/templates/odoo/docker-compose.yml
@@ -15,7 +15,8 @@ services:
db:
image: postgres:13
-
+ networks:
+ - dokploy-network
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=odoo
diff --git a/apps/dokploy/templates/open-webui/docker-compose.yml b/apps/dokploy/templates/open-webui/docker-compose.yml
index ee179721..d396dacc 100644
--- a/apps/dokploy/templates/open-webui/docker-compose.yml
+++ b/apps/dokploy/templates/open-webui/docker-compose.yml
@@ -3,7 +3,8 @@ services:
ollama:
volumes:
- ollama:/root/.ollama
-
+ networks:
+ - dokploy-network
pull_policy: always
tty: true
restart: unless-stopped
diff --git a/apps/dokploy/templates/outline/docker-compose.yml b/apps/dokploy/templates/outline/docker-compose.yml
deleted file mode 100644
index aaf98ac0..00000000
--- a/apps/dokploy/templates/outline/docker-compose.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-services:
- outline:
- image: outlinewiki/outline:0.82.0
- restart: always
- depends_on:
- - postgres
- - redis
- - dex
- ports:
- - 3000
- environment:
- NODE_ENV: production
- URL: ${URL}
- FORCE_HTTPS: 'false'
- SECRET_KEY: ${SECRET_KEY}
- UTILS_SECRET: ${UTILS_SECRET}
- DATABASE_URL: postgres://outline:${POSTGRES_PASSWORD}@postgres:5432/outline
- PGSSLMODE: disable
- REDIS_URL: redis://redis:6379
- OIDC_CLIENT_ID: outline
- OIDC_CLIENT_SECRET: ${CLIENT_SECRET}
- OIDC_AUTH_URI: ${DEX_URL}/auth
- OIDC_TOKEN_URI: ${DEX_URL}/token
- OIDC_USERINFO_URI: ${DEX_URL}/userinfo
-
- dex:
- image: ghcr.io/dexidp/dex:v2.37.0
- restart: always
- volumes:
- - ../files/etc/dex/config.yaml:/etc/dex/config.yaml
- command:
- - dex
- - serve
- - /etc/dex/config.yaml
- ports:
- - 5556
-
- postgres:
- image: postgres:15
- restart: always
- environment:
- POSTGRES_DB: outline
- POSTGRES_USER: outline
- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
- volumes:
- - postgres_data-test-outline-khufpx:/var/lib/postgresql/data
-
- redis:
- image: redis:latest
- restart: always
- command: redis-server --appendonly yes
- volumes:
- - redis_data-test-outline-khufpx:/data
-
-volumes:
- postgres_data-test-outline-khufpx:
- redis_data-test-outline-khufpx:
\ No newline at end of file
diff --git a/apps/dokploy/templates/outline/index.ts b/apps/dokploy/templates/outline/index.ts
deleted file mode 100644
index 8431e568..00000000
--- a/apps/dokploy/templates/outline/index.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateBase64,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
- const dexDomain = generateRandomDomain(schema);
- const SECRET_KEY = generateBase64(32);
- const UTILS_SECRET = generateBase64(32);
- const CLIENT_SECRET = generateBase64(32);
- const POSTGRES_PASSWORD = generatePassword();
-
- const mainURL = `http://${mainDomain}`;
- const dexURL = `http://${dexDomain}`;
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 3000,
- serviceName: "outline",
- },
- {
- host: dexDomain,
- port: 5556,
- serviceName: "dex",
- },
- ];
-
- const mounts: Template["mounts"] = [
- {
- filePath: "/etc/dex/config.yaml",
- content: `issuer: ${dexURL}
-
-web:
- http: 0.0.0.0:5556
-
-storage:
- type: memory
-
-enablePasswordDB: true
-
-frontend:
- issuer: Outline
-
-logger:
- level: debug
-
-staticPasswords:
- - email: "admin@example.com"
- # bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2)
- hash: "$2y$10$jsRWHw54uxTUIfhjgUrB9u8HSzPk7TUuQri9sXZrKzRXcScvwYor."
- username: "admin"
- userID: "1"
-
-
-oauth2:
- skipApprovalScreen: true
- alwaysShowLoginScreen: false
- passwordConnector: local
-
-staticClients:
- - id: "outline"
- redirectURIs:
- - ${mainURL}/auth/oidc.callback
- name: "Outline"
- secret: "${CLIENT_SECRET}"`,
- },
- ];
-
- const envs = [
- `URL=${mainURL}`,
- `DEX_URL=${dexURL}`,
- `DOMAIN_NAME=${mainDomain}`,
- `POSTGRES_PASSWORD=${POSTGRES_PASSWORD}`,
- `SECRET_KEY=${SECRET_KEY}`,
- `UTILS_SECRET=${UTILS_SECRET}`,
- `CLIENT_SECRET=${CLIENT_SECRET}`,
- ];
-
- return {
- domains,
- envs,
- mounts,
- };
-}
diff --git a/apps/dokploy/templates/penpot/docker-compose.yml b/apps/dokploy/templates/penpot/docker-compose.yml
index 3e0efe91..55abdb53 100644
--- a/apps/dokploy/templates/penpot/docker-compose.yml
+++ b/apps/dokploy/templates/penpot/docker-compose.yml
@@ -46,7 +46,8 @@ services:
- penpot-backend
- penpot-exporter
-
+ networks:
+ - dokploy-network
environment:
PENPOT_FLAGS: disable-email-verification enable-smtp enable-prepl-server disable-secure-session-cookies
@@ -62,7 +63,8 @@ services:
- penpot-postgres
- penpot-redis
-
+ networks:
+ - dokploy-network
## Configuration envronment variables for the backend
## container.
@@ -141,7 +143,8 @@ services:
penpot-exporter:
image: "penpotapp/exporter:2.3.2"
restart: always
-
+ networks:
+ - dokploy-network
environment:
# Don't touch it; this uses an internal docker network to
@@ -159,7 +162,8 @@ services:
volumes:
- penpot_postgres_v15:/var/lib/postgresql/data
-
+ networks:
+ - dokploy-network
environment:
- POSTGRES_INITDB_ARGS=--data-checksums
@@ -170,7 +174,8 @@ services:
penpot-redis:
image: redis:7.2
restart: always
-
+ networks:
+ - dokploy-network
## A mailcatch service, used as temporal SMTP server. You can access via HTTP to the
## port 1080 for read all emails the penpot platform has sent. Should be only used as a
@@ -183,7 +188,8 @@ services:
- '1025'
ports:
- 1080
-
+ networks:
+ - dokploy-network
## Example configuration of MiniIO (S3 compatible object storage service); If you don't
## have preference, then just use filesystem, this is here just for the completeness.
diff --git a/apps/dokploy/templates/penpot/index.ts b/apps/dokploy/templates/penpot/index.ts
index a3e90e8a..f657c698 100644
--- a/apps/dokploy/templates/penpot/index.ts
+++ b/apps/dokploy/templates/penpot/index.ts
@@ -2,6 +2,8 @@ import {
type DomainSchema,
type Schema,
type Template,
+ generateBase64,
+ generatePassword,
generateRandomDomain,
} from "../utils";
diff --git a/apps/dokploy/templates/peppermint/docker-compose.yml b/apps/dokploy/templates/peppermint/docker-compose.yml
index 06fb46c6..305c5eb9 100644
--- a/apps/dokploy/templates/peppermint/docker-compose.yml
+++ b/apps/dokploy/templates/peppermint/docker-compose.yml
@@ -4,7 +4,8 @@ services:
peppermint-postgres:
image: postgres:latest
restart: always
-
+ networks:
+ - dokploy-network
volumes:
- peppermint-postgres-data:/var/lib/postgresql/data
environment:
@@ -20,7 +21,8 @@ services:
peppermint-app:
image: pepperlabs/peppermint:latest
restart: always
-
+ networks:
+ - dokploy-network
depends_on:
peppermint-postgres:
condition: service_healthy
diff --git a/apps/dokploy/templates/photoprism/docker-compose.yml b/apps/dokploy/templates/photoprism/docker-compose.yml
index 56793dbd..285f2ff8 100644
--- a/apps/dokploy/templates/photoprism/docker-compose.yml
+++ b/apps/dokploy/templates/photoprism/docker-compose.yml
@@ -7,7 +7,8 @@ services:
security_opt:
- seccomp:unconfined
- apparmor:unconfined
-
+ networks:
+ - dokploy-network
environment:
PHOTOPRISM_ADMIN_USER: "admin"
PHOTOPRISM_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
@@ -56,7 +57,8 @@ services:
image: mariadb:11
restart: unless-stopped
stop_grace_period: 5s
-
+ networks:
+ - dokploy-network
security_opt:
- seccomp:unconfined
- apparmor:unconfined
diff --git a/apps/dokploy/templates/photoprism/index.ts b/apps/dokploy/templates/photoprism/index.ts
index 4a103a62..d20ac29c 100644
--- a/apps/dokploy/templates/photoprism/index.ts
+++ b/apps/dokploy/templates/photoprism/index.ts
@@ -2,6 +2,7 @@ import {
type DomainSchema,
type Schema,
type Template,
+ generateHash,
generatePassword,
generateRandomDomain,
} from "../utils";
diff --git a/apps/dokploy/templates/phpmyadmin/docker-compose.yml b/apps/dokploy/templates/phpmyadmin/docker-compose.yml
index 91674e87..1f775f09 100644
--- a/apps/dokploy/templates/phpmyadmin/docker-compose.yml
+++ b/apps/dokploy/templates/phpmyadmin/docker-compose.yml
@@ -10,7 +10,8 @@ services:
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- db_data:/var/lib/mysql
-
+ networks:
+ - dokploy-network
phpmyadmin:
image: phpmyadmin/phpmyadmin:5.2.1
diff --git a/apps/dokploy/templates/plausible/docker-compose.yml b/apps/dokploy/templates/plausible/docker-compose.yml
index ad483ecf..bb267f65 100644
--- a/apps/dokploy/templates/plausible/docker-compose.yml
+++ b/apps/dokploy/templates/plausible/docker-compose.yml
@@ -1,8 +1,10 @@
+version: "3.8"
services:
plausible_db:
image: postgres:16-alpine
restart: always
-
+ networks:
+ - dokploy-network
volumes:
- db-data:/var/lib/postgresql/data
environment:
@@ -11,7 +13,8 @@ services:
plausible_events_db:
image: clickhouse/clickhouse-server:24.3.3.102-alpine
restart: always
-
+ networks:
+ - dokploy-network
volumes:
- event-data:/var/lib/clickhouse
- event-logs:/var/log/clickhouse-server
@@ -23,7 +26,7 @@ services:
hard: 262144
plausible:
- image: ghcr.io/plausible/community-edition:v2.1.5
+ image: ghcr.io/plausible/community-edition:v2.1.4
restart: always
command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
depends_on:
diff --git a/apps/dokploy/templates/pocket-id/docker-compose.yml b/apps/dokploy/templates/pocket-id/docker-compose.yml
deleted file mode 100644
index f9385143..00000000
--- a/apps/dokploy/templates/pocket-id/docker-compose.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-services:
- pocket-id:
- image: ghcr.io/pocket-id/pocket-id:v0.35.1
- restart: unless-stopped
- environment:
- - PUBLIC_UI_CONFIG_DISABLED
- - PUBLIC_APP_URL
- - TRUST_PROXY
- ports:
- - 80
- volumes:
- - pocket-id-data:/app/backend/data
- healthcheck:
- test: "curl -f http://localhost/health"
- interval: 1m30s
- timeout: 5s
- retries: 2
- start_period: 10s
-
-volumes:
- pocket-id-data:
diff --git a/apps/dokploy/templates/pocket-id/index.ts b/apps/dokploy/templates/pocket-id/index.ts
deleted file mode 100644
index 9a9faa2a..00000000
--- a/apps/dokploy/templates/pocket-id/index.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mainDomain = generateRandomDomain(schema);
-
- const domains: DomainSchema[] = [
- {
- host: mainDomain,
- port: 80,
- serviceName: "pocket-id",
- },
- ];
-
- const envs = [
- "PUBLIC_UI_CONFIG_DISABLED=false",
- `PUBLIC_APP_URL=http://${mainDomain}`,
- "TRUST_PROXY=true",
- ];
-
- return {
- domains,
- envs,
- };
-}
diff --git a/apps/dokploy/templates/portainer/docker-compose.yml b/apps/dokploy/templates/portainer/docker-compose.yml
index 19e67a3e..fa4fe410 100644
--- a/apps/dokploy/templates/portainer/docker-compose.yml
+++ b/apps/dokploy/templates/portainer/docker-compose.yml
@@ -6,7 +6,8 @@ services:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/volumes:/var/lib/docker/volumes
-
+ networks:
+ - dokploy-network
deploy:
mode: global
diff --git a/apps/dokploy/templates/postiz/docker-compose.yml b/apps/dokploy/templates/postiz/docker-compose.yml
index cd06e795..f842c92d 100644
--- a/apps/dokploy/templates/postiz/docker-compose.yml
+++ b/apps/dokploy/templates/postiz/docker-compose.yml
@@ -4,7 +4,8 @@ services:
postiz-app:
image: ghcr.io/gitroomhq/postiz-app:latest
restart: always
-
+ networks:
+ - dokploy-network
environment:
MAIN_URL: "https://${POSTIZ_HOST}"
FRONTEND_URL: "https://${POSTIZ_HOST}"
@@ -29,7 +30,8 @@ services:
postiz-postgres:
image: postgres:17-alpine
restart: always
-
+ networks:
+ - dokploy-network
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USER}
@@ -45,7 +47,8 @@ services:
postiz-redis:
image: redis:7.2
restart: always
-
+ networks:
+ - dokploy-network
healthcheck:
test: redis-cli ping
interval: 10s
diff --git a/apps/dokploy/templates/registry/docker-compose.yml b/apps/dokploy/templates/registry/docker-compose.yml
deleted file mode 100644
index 08c5c368..00000000
--- a/apps/dokploy/templates/registry/docker-compose.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-services:
- registry:
- restart: always
- image: registry:2
- ports:
- - 5000
- volumes:
- - ../files/auth/registry.password:/auth/registry.password
- - registry-data:/var/lib/registry
- environment:
- REGISTRY_STORAGE_DELETE_ENABLED: true
- REGISTRY_HEALTH_STORAGEDRIVER_ENABLED: false
- REGISTRY_HTTP_SECRET: ${REGISTRY_HTTP_SECRET}
- REGISTRY_AUTH: htpasswd
- REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
- REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
-
-volumes:
- registry-data:
\ No newline at end of file
diff --git a/apps/dokploy/templates/registry/index.ts b/apps/dokploy/templates/registry/index.ts
deleted file mode 100644
index 81965e6e..00000000
--- a/apps/dokploy/templates/registry/index.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const domains: DomainSchema[] = [
- {
- host: generateRandomDomain(schema),
- port: 5000,
- serviceName: "registry",
- },
- ];
-
- const registryHttpSecret = generatePassword(30);
-
- const envs = [`REGISTRY_HTTP_SECRET=${registryHttpSecret}`];
-
- const mounts: Template["mounts"] = [
- {
- filePath: "/auth/registry.password",
- content:
- "# from: docker run --rm --entrypoint htpasswd httpd:2 -Bbn docker password\ndocker:$2y$10$qWZoWev/u5PV7WneFoRAMuoGpRcAQOgUuIIdLnU7pJXogrBSY23/2\n",
- },
- ];
-
- return {
- domains,
- envs,
- mounts,
- };
-}
diff --git a/apps/dokploy/templates/rocketchat/docker-compose.yml b/apps/dokploy/templates/rocketchat/docker-compose.yml
index 5119f5a4..751bd845 100644
--- a/apps/dokploy/templates/rocketchat/docker-compose.yml
+++ b/apps/dokploy/templates/rocketchat/docker-compose.yml
@@ -28,7 +28,8 @@ services:
MONGODB_ADVERTISED_HOSTNAME: mongodb
MONGODB_ENABLE_JOURNAL: true
ALLOW_EMPTY_PASSWORD: yes
-
+ networks:
+ - dokploy-network
volumes:
mongodb_data: { driver: local }
diff --git a/apps/dokploy/templates/roundcube/docker-compose.yml b/apps/dokploy/templates/roundcube/docker-compose.yml
index e5ba4a8b..440f907d 100644
--- a/apps/dokploy/templates/roundcube/docker-compose.yml
+++ b/apps/dokploy/templates/roundcube/docker-compose.yml
@@ -9,7 +9,8 @@ services:
- ROUNDCUBEMAIL_SKIN=elastic
- ROUNDCUBEMAIL_DEFAULT_HOST=${DEFAULT_HOST}
- ROUNDCUBEMAIL_SMTP_SERVER=${SMTP_SERVER}
-
+ networks:
+ - dokploy-network
networks:
dokploy-network:
diff --git a/apps/dokploy/templates/ryot/docker-compose.yml b/apps/dokploy/templates/ryot/docker-compose.yml
index 09a72707..1fcd80ed 100644
--- a/apps/dokploy/templates/ryot/docker-compose.yml
+++ b/apps/dokploy/templates/ryot/docker-compose.yml
@@ -3,7 +3,8 @@ version: '3.7'
services:
ryot-app:
image: ignisda/ryot:v7.10
-
+ networks:
+ - dokploy-network
environment:
- DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@ryot-db:5432/postgres
- SERVER_ADMIN_ACCESS_TOKEN=${ADMIN_ACCESS_TOKEN}
@@ -18,7 +19,8 @@ services:
ryot-db:
image: postgres:16-alpine
-
+ networks:
+ - dokploy-network
volumes:
- ryot-postgres-data:/var/lib/postgresql/data
environment:
diff --git a/apps/dokploy/templates/shlink/docker-compose.yml b/apps/dokploy/templates/shlink/docker-compose.yml
deleted file mode 100644
index 6d15a26d..00000000
--- a/apps/dokploy/templates/shlink/docker-compose.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-services:
- shlink:
- image: shlinkio/shlink:stable
- environment:
- - INITIAL_API_KEY=${INITIAL_API_KEY}
- - DEFAULT_DOMAIN=${DEFAULT_DOMAIN}
- # Note: you should also update SHLINK_SERVER_URL in the shlink-web service.
- - IS_HTTPS_ENABLED=false
- volumes:
- - shlink-data:/etc/shlink/data
- healthcheck:
- test: ["CMD", "curl", "-f", "http://127.0.0.1:8080/rest/v3/health"]
- interval: 30s
- timeout: 10s
- retries: 3
- shlink-web:
- image: shlinkio/shlink-web-client
- environment:
- - SHLINK_SERVER_API_KEY=${INITIAL_API_KEY}
- # Note: if you've set IS_HTTPS_ENABLED=true, change http to https.
- - SHLINK_SERVER_URL=http://${DEFAULT_DOMAIN}
- healthcheck:
- test: ["CMD", "curl", "-f", "http://127.0.0.1:8080"]
- interval: 30s
- timeout: 10s
- retries: 3
-
-volumes:
- shlink-data:
diff --git a/apps/dokploy/templates/shlink/index.ts b/apps/dokploy/templates/shlink/index.ts
deleted file mode 100644
index 1e456e1c..00000000
--- a/apps/dokploy/templates/shlink/index.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const defaultDomain = generateRandomDomain(schema);
- const initialApiKey = generatePassword(30);
-
- const domains: DomainSchema[] = [
- {
- host: `web-${defaultDomain}`,
- port: 8080,
- serviceName: "shlink-web",
- },
- {
- host: defaultDomain,
- port: 8080,
- serviceName: "shlink",
- },
- ];
-
- const envs = [
- `INITIAL_API_KEY=${initialApiKey}`,
- `DEFAULT_DOMAIN=${defaultDomain}`,
- ];
-
- return {
- envs,
- domains,
- };
-}
diff --git a/apps/dokploy/templates/slash/docker-compose.yml b/apps/dokploy/templates/slash/docker-compose.yml
index ee6cdf89..75afc478 100644
--- a/apps/dokploy/templates/slash/docker-compose.yml
+++ b/apps/dokploy/templates/slash/docker-compose.yml
@@ -3,7 +3,8 @@ version: "3.8"
services:
slash-app:
image: yourselfhosted/slash:latest
-
+ networks:
+ - dokploy-network
volumes:
- slash-app-data:/var/opt/slash
environment:
@@ -16,7 +17,8 @@ services:
slash-postgres:
image: postgres:16-alpine
-
+ networks:
+ - dokploy-network
volumes:
- slash-postgres-data:/var/lib/postgresql/data
environment:
diff --git a/apps/dokploy/templates/spacedrive/docker-compose.yml b/apps/dokploy/templates/spacedrive/docker-compose.yml
deleted file mode 100644
index b98d55ab..00000000
--- a/apps/dokploy/templates/spacedrive/docker-compose.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-services:
- server:
- image: ghcr.io/spacedriveapp/spacedrive/server:latest
- ports:
- - 8080
- environment:
- - SD_AUTH=${SD_USERNAME}:${SD_PASSWORD}
- volumes:
- - /var/spacedrive:/var/spacedrive
diff --git a/apps/dokploy/templates/spacedrive/index.ts b/apps/dokploy/templates/spacedrive/index.ts
deleted file mode 100644
index 15db4b19..00000000
--- a/apps/dokploy/templates/spacedrive/index.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const randomDomain = generateRandomDomain(schema);
- const secretKey = generatePassword();
- const randomUsername = "admin"; // Default username
-
- const domains: DomainSchema[] = [
- {
- host: randomDomain,
- port: 8080,
- serviceName: "server",
- },
- ];
-
- const envs = [`SD_USERNAME=${randomUsername}`, `SD_PASSWORD=${secretKey}`];
-
- return {
- envs,
- domains,
- };
-}
diff --git a/apps/dokploy/templates/supabase/docker-compose.yml b/apps/dokploy/templates/supabase/docker-compose.yml
index 89339736..e1e187fd 100644
--- a/apps/dokploy/templates/supabase/docker-compose.yml
+++ b/apps/dokploy/templates/supabase/docker-compose.yml
@@ -11,7 +11,8 @@ services:
studio:
container_name: supabase-studio
image: supabase/studio:20240729-ce42139
-
+ networks:
+ - dokploy-network
restart: unless-stopped
healthcheck:
test:
@@ -52,7 +53,8 @@ services:
container_name: supabase-kong
image: kong:2.8.1
restart: unless-stopped
-
+ networks:
+ - dokploy-network
# https://unix.stackexchange.com/a/294837
entrypoint: bash -c 'eval "echo \"$$(cat ~/temp.yml)\"" > ~/kong.yml && /docker-entrypoint.sh kong docker-start'
#ports:
@@ -83,7 +85,8 @@ services:
auth:
container_name: supabase-auth
image: supabase/gotrue:v2.158.1
-
+ networks:
+ - dokploy-network
depends_on:
db:
# Disable this if you are using an external Postgres database
@@ -154,7 +157,8 @@ services:
rest:
container_name: supabase-rest
image: postgrest/postgrest:v12.2.0
-
+ networks:
+ - dokploy-network
depends_on:
db:
# Disable this if you are using an external Postgres database
@@ -176,7 +180,8 @@ services:
# This container name looks inconsistent but is correct because realtime constructs tenant id by parsing the subdomain
container_name: realtime-dev.supabase-realtime
image: supabase/realtime:v2.30.23
-
+ networks:
+ - dokploy-network
depends_on:
db:
# Disable this if you are using an external Postgres database
@@ -221,7 +226,8 @@ services:
storage:
container_name: supabase-storage
image: supabase/storage-api:v1.0.6
-
+ networks:
+ - dokploy-network
depends_on:
db:
# Disable this if you are using an external Postgres database
@@ -265,7 +271,8 @@ services:
imgproxy:
container_name: supabase-imgproxy
image: darthsim/imgproxy:v3.8.0
-
+ networks:
+ - dokploy-network
healthcheck:
test: ["CMD", "imgproxy", "health"]
timeout: 5s
@@ -282,7 +289,8 @@ services:
meta:
container_name: supabase-meta
image: supabase/postgres-meta:v0.83.2
-
+ networks:
+ - dokploy-network
depends_on:
db:
# Disable this if you are using an external Postgres database
@@ -302,7 +310,8 @@ services:
container_name: supabase-edge-functions
image: supabase/edge-runtime:v1.56.0
restart: unless-stopped
-
+ networks:
+ - dokploy-network
depends_on:
analytics:
condition: service_healthy
@@ -324,7 +333,8 @@ services:
analytics:
container_name: supabase-analytics
image: supabase/logflare:1.4.0
-
+ networks:
+ - dokploy-network
healthcheck:
test: ["CMD", "curl", "http://localhost:4000/health"]
timeout: 5s
@@ -370,7 +380,8 @@ services:
db:
container_name: supabase-db
image: supabase/postgres:15.1.1.78
-
+ networks:
+ - dokploy-network
healthcheck:
test: pg_isready -U postgres -h localhost
interval: 5s
@@ -419,7 +430,8 @@ services:
vector:
container_name: supabase-vector
image: timberio/vector:0.28.1-alpine
-
+ networks:
+ - dokploy-network
healthcheck:
test:
[
diff --git a/apps/dokploy/templates/superset/docker-compose.yml b/apps/dokploy/templates/superset/docker-compose.yml
deleted file mode 100644
index b73bf55e..00000000
--- a/apps/dokploy/templates/superset/docker-compose.yml
+++ /dev/null
@@ -1,87 +0,0 @@
-# This is an UNOFFICIAL production docker image build for Superset:
-# - https://github.com/amancevice/docker-superset
-
-
-# ## SETUP INSTRUCTIONS
-#
-# After deploying this image, you will need to run one of the two
-# commands below in a terminal within the superset container:
-# $ superset-demo # Initialise database + load demo charts/datasets
-# $ superset-init # Initialise database only
-#
-# You will be prompted to enter the credentials for the admin user.
-
-
-# ## NETWORK INSTRUCTIONS
-#
-# If you want to connect superset with other internal databases managed by
-# Dokploy (on dokploy-network) using internal hostnames, you will need to
-# uncomment the `networks` section, both for the superset container and
-# at the very bottom of this docker-compose template.
-#
-# Note that the `superset` service name/hostname will not be unique on the
-# global `dokploy-network`. If you plan to:
-#
-# 1. deploy a second instance of superset on dokploy-network, and
-# 2. have other containers on dokploy-network utilise the second instance's
-# Superset API (https://superset.apache.org/docs/api)
-#
-# Please change the service name of the second instance.
-
-services:
- superset:
- image: amancevice/superset
- restart: always
- #networks:
- # - dokploy-network
- depends_on:
- - superset_postgres
- - superset_redis
- volumes:
- # This superset_config.py can be edited in Dokploy's UI Advanced -> Volume Mount
- - ../files/superset/superset_config.py:/etc/superset/superset_config.py
- environment:
- SECRET_KEY: ${SECRET_KEY}
- MAPBOX_API_KEY: ${MAPBOX_API_KEY}
- POSTGRES_USER: ${POSTGRES_USER}
- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
- POSTGRES_DB: ${POSTGRES_DB}
- REDIS_PASSWORD: ${REDIS_PASSWORD}
- # Ensure the hosts matches your service names below.
- POSTGRES_HOST: superset_postgres
- REDIS_HOST: superset_redis
-
- superset_postgres:
- image: postgres
- restart: always
- environment:
- POSTGRES_USER: ${POSTGRES_USER}
- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
- POSTGRES_DB: ${POSTGRES_DB}
- volumes:
- - superset_postgres_data:/var/lib/postgresql/data
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
- interval: 30s
- timeout: 10s
- retries: 3
-
-superset_redis:
- image: redis
- restart: always
- volumes:
- - superset_redis_data:/data
- command: redis-server --requirepass ${REDIS_PASSWORD}
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
- interval: 30s
- timeout: 10s
- retries: 3
-
-#networks:
-# dokploy-network:
-# external: true
-
-volumes:
- superset_postgres_data:
- superset_redis_data:
diff --git a/apps/dokploy/templates/superset/index.ts b/apps/dokploy/templates/superset/index.ts
deleted file mode 100644
index 954fc971..00000000
--- a/apps/dokploy/templates/superset/index.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generatePassword,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const mapboxApiKey = "";
- const secretKey = generatePassword(30);
- const postgresDb = "superset";
- const postgresUser = "superset";
- const postgresPassword = generatePassword(30);
- const redisPassword = generatePassword(30);
-
- const domains: DomainSchema[] = [
- {
- host: generateRandomDomain(schema),
- port: 8088,
- serviceName: "superset",
- },
- ];
-
- const envs = [
- `SECRET_KEY=${secretKey}`,
- `MAPBOX_API_KEY=${mapboxApiKey}`,
- `POSTGRES_DB=${postgresDb}`,
- `POSTGRES_USER=${postgresUser}`,
- `POSTGRES_PASSWORD=${postgresPassword}`,
- `REDIS_PASSWORD=${redisPassword}`,
- ];
-
- const mounts: Template["mounts"] = [
- {
- filePath: "./superset/superset_config.py",
- content: `
-"""
-For more configuration options, see:
-- https://superset.apache.org/docs/configuration/configuring-superset
-"""
-
-import os
-
-SECRET_KEY = os.getenv("SECRET_KEY")
-MAPBOX_API_KEY = os.getenv("MAPBOX_API_KEY", "")
-
-CACHE_CONFIG = {
- "CACHE_TYPE": "RedisCache",
- "CACHE_DEFAULT_TIMEOUT": 300,
- "CACHE_KEY_PREFIX": "superset_",
- "CACHE_REDIS_HOST": "redis",
- "CACHE_REDIS_PORT": 6379,
- "CACHE_REDIS_DB": 1,
- "CACHE_REDIS_URL": f"redis://:{os.getenv('REDIS_PASSWORD')}@{os.getenv('REDIS_HOST')}:6379/1",
-}
-
-FILTER_STATE_CACHE_CONFIG = {**CACHE_CONFIG, "CACHE_KEY_PREFIX": "superset_filter_"}
-EXPLORE_FORM_DATA_CACHE_CONFIG = {**CACHE_CONFIG, "CACHE_KEY_PREFIX": "superset_explore_form_"}
-
-SQLALCHEMY_TRACK_MODIFICATIONS = True
-SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{os.getenv('POSTGRES_USER')}:{os.getenv('POSTGRES_PASSWORD')}@{os.getenv('POSTGRES_HOST')}:5432/{os.getenv('POSTGRES_DB')}"
-
-# Uncomment if you want to load example data (using "superset load_examples") at the
-# same location as your metadata postgresql instance. Otherwise, the default sqlite
-# will be used, which will not persist in volume when restarting superset by default.
-#SQLALCHEMY_EXAMPLES_URI = SQLALCHEMY_DATABASE_URI
- `.trim(),
- },
- ];
-
- return {
- envs,
- domains,
- mounts,
- };
-}
diff --git a/apps/dokploy/templates/teable/docker-compose.yml b/apps/dokploy/templates/teable/docker-compose.yml
index 386e3773..b96b677c 100644
--- a/apps/dokploy/templates/teable/docker-compose.yml
+++ b/apps/dokploy/templates/teable/docker-compose.yml
@@ -2,7 +2,7 @@ version: "3.9"
services:
teable:
- image: ghcr.io/teableio/teable:latest
+ image: ghcr.io/teableio/teable:1.3.1-alpha-build.460
restart: always
volumes:
- teable-data:/app/.assets
@@ -41,7 +41,8 @@ services:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
-
+ networks:
+ - dokploy-network
healthcheck:
test:
[
@@ -57,7 +58,8 @@ services:
environment:
- TZ=${TIMEZONE}
- PRISMA_DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
-
+ networks:
+ - dokploy-network
depends_on:
teable-db:
condition: service_healthy
diff --git a/apps/dokploy/templates/templates.ts b/apps/dokploy/templates/templates.ts
index d39465a8..9531eb7a 100644
--- a/apps/dokploy/templates/templates.ts
+++ b/apps/dokploy/templates/templates.ts
@@ -1,37 +1,6 @@
import type { TemplateData } from "./types/templates-data.type";
export const templates: TemplateData[] = [
- {
- id: "appwrite",
- name: "Appwrite",
- version: "1.6.0",
- description:
- "Appwrite is an end-to-end backend server for Web, Mobile, Native, or Backend apps. Appwrite abstracts the complexity and repetitiveness required to build a modern backend API from scratch and allows you to build secure apps faster.\n" +
- "Using Appwrite, you can easily integrate your app with user authentication and multiple sign-in methods, a database for storing and querying users and team data, storage and file management, image manipulation, Cloud Functions, messaging, and more services.",
- links: {
- github: "https://github.com/appwrite/appwrite",
- website: "https://appwrite.io/",
- docs: "https://appwrite.io/docs",
- },
- logo: "appwrite.svg",
- tags: ["database", "firebase", "postgres"],
- load: () => import("./appwrite/index").then((m) => m.generate),
- },
- {
- id: "outline",
- name: "Outline",
- version: "0.82.0",
- description:
- "Outline is a self-hosted knowledge base and documentation platform that allows you to build and manage your own knowledge base applications.",
- links: {
- github: "https://github.com/outline/outline",
- website: "https://getoutline.com/",
- docs: "https://docs.getoutline.com/s/guide",
- },
- logo: "outline.png",
- load: () => import("./outline/index").then((m) => m.generate),
- tags: ["documentation", "knowledge-base", "self-hosted"],
- },
{
id: "supabase",
name: "SupaBase",
@@ -65,7 +34,7 @@ export const templates: TemplateData[] = [
{
id: "plausible",
name: "Plausible",
- version: "v2.1.5",
+ version: "v2.1.4",
description:
"Plausible is a open source, self-hosted web analytics platform that lets you track website traffic and user behavior.",
logo: "plausible.svg",
@@ -201,7 +170,7 @@ export const templates: TemplateData[] = [
{
id: "wordpress",
name: "Wordpress",
- version: "6.7.1",
+ version: "5.8.3",
description:
"Wordpress is a free and open source content management system (CMS) for publishing and managing websites.",
logo: "wordpress.png",
@@ -393,21 +362,6 @@ export const templates: TemplateData[] = [
tags: ["chat"],
load: () => import("./open-webui/index").then((m) => m.generate),
},
- {
- id: "mailpit",
- name: "Mailpit",
- version: "v1.22.3",
- description:
- "Mailpit is a tiny, self-contained, and secure email & SMTP testing tool with API for developers.",
- logo: "mailpit.svg",
- links: {
- github: "https://github.com/axllent/mailpit",
- website: "https://mailpit.axllent.org/",
- docs: "https://mailpit.axllent.org/docs/",
- },
- tags: ["email", "smtp"],
- load: () => import("./mailpit/index").then((m) => m.generate),
- },
{
id: "listmonk",
name: "Listmonk",
@@ -441,7 +395,7 @@ export const templates: TemplateData[] = [
{
id: "umami",
name: "Umami",
- version: "v2.16.1",
+ version: "v2.14.0",
description:
"Umami is a simple, fast, privacy-focused alternative to Google Analytics.",
logo: "umami.png",
@@ -584,7 +538,7 @@ export const templates: TemplateData[] = [
website: "https://filebrowser.org/",
docs: "https://filebrowser.org/",
},
- tags: ["file-manager", "storage"],
+ tags: ["file", "manager"],
load: () => import("./filebrowser/index").then((m) => m.generate),
},
{
@@ -677,21 +631,6 @@ export const templates: TemplateData[] = [
tags: ["open-source"],
load: () => import("./vaultwarden/index").then((m) => m.generate),
},
- {
- id: "linkwarden",
- name: "Linkwarden",
- version: "2.9.3",
- description:
- "Self-hosted, open-source collaborative bookmark manager to collect, organize and archive webpages.",
- logo: "linkwarden.png",
- links: {
- github: "https://github.com/linkwarden/linkwarden",
- website: "https://linkwarden.app/",
- docs: "https://docs.linkwarden.app/",
- },
- tags: ["bookmarks", "link-sharing"],
- load: () => import("./linkwarden/index").then((m) => m.generate),
- },
{
id: "hi-events",
name: "Hi.events",
@@ -895,7 +834,7 @@ export const templates: TemplateData[] = [
website: "https://nextcloud.com/",
docs: "https://docs.nextcloud.com/",
},
- tags: ["file-manager", "sync"],
+ tags: ["file", "sync"],
load: () => import("./nextcloud-aio/index").then((m) => m.generate),
},
{
@@ -1123,21 +1062,6 @@ export const templates: TemplateData[] = [
tags: ["identity", "auth"],
load: () => import("./logto/index").then((m) => m.generate),
},
- {
- id: "pocket-id",
- name: "Pocket ID",
- version: "0.35.1",
- description:
- "A simple and easy-to-use OIDC provider that allows users to authenticate with their passkeys to your services.",
- logo: "pocket-id.svg",
- links: {
- github: "https://github.com/pocket-id/pocket-id",
- website: "https://pocket-id.org/",
- docs: "https://pocket-id.org/docs",
- },
- tags: ["identity", "auth"],
- load: () => import("./pocket-id/index").then((m) => m.generate),
- },
{
id: "penpot",
name: "Penpot",
@@ -1150,7 +1074,7 @@ export const templates: TemplateData[] = [
website: "https://penpot.app/",
docs: "https://docs.penpot.app/",
},
- tags: ["design", "collaboration"],
+ tags: ["desing", "collaboration"],
load: () => import("./penpot/index").then((m) => m.generate),
},
{
@@ -1171,9 +1095,9 @@ export const templates: TemplateData[] = [
{
id: "unsend",
name: "Unsend",
- version: "v1.3.2",
+ version: "v1.2.4",
description: "Open source alternative to Resend,Sendgrid, Postmark etc. ",
- logo: "unsend.png",
+ logo: "unsend.png", // we defined the name and the extension of the logo
links: {
github: "https://github.com/unsend-dev/unsend",
website: "https://unsend.dev/",
@@ -1315,21 +1239,6 @@ export const templates: TemplateData[] = [
tags: ["matrix", "communication"],
load: () => import("./conduit/index").then((m) => m.generate),
},
- {
- id: "evolutionapi",
- name: "Evolution API",
- version: "v2.1.2",
- description:
- "Evolution API is a robust platform dedicated to empowering small businesses with limited resources, going beyond a simple messaging solution via WhatsApp.",
- logo: "evolutionapi.png",
- links: {
- github: "https://github.com/EvolutionAPI/evolution-api",
- docs: "https://doc.evolution-api.com/v2/en/get-started/introduction",
- website: "https://evolution-api.com/opensource-whatsapp-api/",
- },
- tags: ["api", "whatsapp", "messaging"],
- load: () => import("./evolutionapi/index").then((m) => m.generate),
- },
{
id: "conduwuit",
name: "Conduwuit",
@@ -1367,11 +1276,11 @@ export const templates: TemplateData[] = [
version: "latest",
description:
"CouchDB is a document-oriented NoSQL database that excels at replication and horizontal scaling.",
- logo: "couchdb.png",
+ logo: "couchdb.png", // we defined the name and the extension of the logo
links: {
- github: "https://github.com/apache/couchdb",
- website: "https://couchdb.apache.org/",
- docs: "https://docs.couchdb.org/en/stable/",
+ github: "lorem",
+ website: "lorem",
+ docs: "lorem",
},
tags: ["database", "storage"],
load: () => import("./couchdb/index").then((m) => m.generate),
@@ -1389,233 +1298,4 @@ export const templates: TemplateData[] = [
tags: ["developer", "tools"],
load: () => import("./it-tools/index").then((m) => m.generate),
},
- {
- id: "superset",
- name: "Superset (Unofficial)",
- version: "latest",
- description: "Data visualization and data exploration platform.",
- logo: "superset.svg",
- links: {
- github: "https://github.com/amancevice/docker-superset",
- website: "https://superset.apache.org",
- docs: "https://superset.apache.org/docs/intro",
- },
- tags: ["analytics", "bi", "dashboard", "database", "sql"],
- load: () => import("./superset/index").then((m) => m.generate),
- },
- {
- id: "glance",
- name: "Glance",
- version: "latest",
- description:
- "A self-hosted dashboard that puts all your feeds in one place. Features RSS feeds, weather, bookmarks, site monitoring, and more in a minimal, fast interface.",
- logo: "glance.png",
- links: {
- github: "https://github.com/glanceapp/glance",
- docs: "https://github.com/glanceapp/glance/blob/main/docs/configuration.md",
- },
- tags: ["dashboard", "monitoring", "widgets", "rss"],
- load: () => import("./glance/index").then((m) => m.generate),
- },
- {
- id: "homarr",
- name: "Homarr",
- version: "latest",
- description:
- "A sleek, modern dashboard that puts all your apps and services in one place with Docker integration.",
- logo: "homarr.png",
- links: {
- github: "https://github.com/homarr-labs/homarr",
- docs: "https://homarr.dev/docs/getting-started/installation/docker",
- website: "https://homarr.dev/",
- },
- tags: ["dashboard", "monitoring"],
- load: () => import("./homarr/index").then((m) => m.generate),
- },
- {
- id: "erpnext",
- name: "ERPNext",
- version: "version-15",
- description: "100% Open Source and highly customizable ERP software.",
- logo: "erpnext.svg",
- links: {
- github: "https://github.com/frappe/erpnext",
- docs: "https://docs.frappe.io/erpnext",
- website: "https://erpnext.com",
- },
- tags: [
- "erp",
- "accounts",
- "manufacturing",
- "retail",
- "sales",
- "pos",
- "hrms",
- ],
- load: () => import("./erpnext/index").then((m) => m.generate),
- },
- {
- id: "maybe",
- name: "Maybe",
- version: "latest",
- description:
- "Maybe is a self-hosted finance tracking application designed to simplify budgeting and expenses.",
- logo: "maybe.svg",
- links: {
- github: "https://github.com/maybe-finance/maybe",
- website: "https://maybe.finance/",
- docs: "https://docs.maybe.finance/",
- },
- tags: ["finance", "self-hosted"],
- load: () => import("./maybe/index").then((m) => m.generate),
- },
- {
- id: "spacedrive",
- name: "Spacedrive",
- version: "latest",
- description:
- "Spacedrive is a cross-platform file manager. It connects your devices together to help you organize files from anywhere. powered by a virtual distributed filesystem (VDFS) written in Rust. Organize files across many devices in one place.",
- links: {
- github: "https://github.com/spacedriveapp/spacedrive",
- website: "https://spacedrive.com/",
- docs: "https://www.spacedrive.com/docs/product/getting-started/introduction",
- },
- logo: "spacedrive.png",
- tags: ["file-manager", "vdfs", "storage"],
- load: () => import("./spacedrive/index").then((m) => m.generate),
- },
- {
- id: "registry",
- name: "Docker Registry",
- version: "2",
- description:
- "Distribution implementation for storing and distributing of Docker container images and artifacts.",
- links: {
- github: "https://github.com/distribution/distribution",
- website: "https://hub.docker.com/_/registry",
- docs: "https://distribution.github.io/distribution/",
- },
- logo: "registry.png",
- tags: ["registry", "docker", "self-hosted"],
- load: () => import("./registry/index").then((m) => m.generate),
- },
- {
- id: "alist",
- name: "AList",
- version: "v3.41.0",
- description:
- "🗂️A file list/WebDAV program that supports multiple storages, powered by Gin and Solidjs.",
- logo: "alist.svg",
- links: {
- github: "https://github.com/AlistGo/alist",
- website: "https://alist.nn.ci",
- docs: "https://alist.nn.ci/guide/install/docker.html",
- },
- tags: ["file", "webdav", "storage"],
- load: () => import("./alist/index").then((m) => m.generate),
- },
- {
- id: "answer",
- name: "Answer",
- version: "v1.4.1",
- description:
- "Answer is an open-source Q&A platform for building a self-hosted question-and-answer service.",
- logo: "answer.png",
- links: {
- github: "https://github.com/apache/answer",
- website: "https://answer.apache.org/",
- docs: "https://answer.apache.org/docs",
- },
- tags: ["q&a", "self-hosted"],
- load: () => import("./answer/index").then((m) => m.generate),
- },
- {
- id: "shlink",
- name: "Shlink",
- version: "stable",
- description:
- "URL shortener that can be used to serve shortened URLs under your own domain.",
- logo: "shlink.svg",
- links: {
- github: "https://github.com/shlinkio/shlink",
- website: "https://shlink.io",
- docs: "https://shlink.io/documentation",
- },
- tags: ["sharing", "shortener", "url"],
- load: () => import("./shlink/index").then((m) => m.generate),
- },
- {
- id: "frappe-hr",
- name: "Frappe HR",
- version: "version-15",
- description:
- "Feature rich HR & Payroll software. 100% FOSS and customizable.",
- logo: "frappe-hr.svg",
- links: {
- github: "https://github.com/frappe/hrms",
- docs: "https://docs.frappe.io/hr",
- website: "https://frappe.io/hr",
- },
- tags: ["hrms", "payroll", "leaves", "expenses", "attendance", "performace"],
- load: () => import("./frappe-hr/index").then((m) => m.generate),
- },
- {
- id: "formbricks",
- name: "Formbricks",
- version: "v3.1.3",
- description:
- "Formbricks is an open-source survey and form platform for collecting user data.",
- logo: "formbricks.png",
- links: {
- github: "https://github.com/formbricks/formbricks",
- website: "https://formbricks.com/",
- docs: "https://formbricks.com/docs",
- },
- tags: ["forms", "analytics"],
- load: () => import("./formbricks/index").then((m) => m.generate),
- },
- {
- id: "trilium",
- name: "Trilium",
- description:
- "Trilium Notes is a hierarchical note taking application with focus on building large personal knowledge bases.",
- logo: "trilium.png",
- version: "latest",
- links: {
- github: "https://github.com/zadam/trilium",
- website: "https://github.com/zadam/trilium",
- docs: "https://github.com/zadam/trilium/wiki/",
- },
- tags: ["self-hosted", "productivity", "personal-use"],
- load: () => import("./trilium/index").then((m) => m.generate),
- },
- {
- id: "convex",
- name: "Convex",
- version: "latest",
- description:
- "Convex is an open-source reactive database designed to make life easy for web app developers.",
- logo: "convex.svg",
- links: {
- github: "https://github.com/get-convex/convex",
- website: "https://www.convex.dev/",
- docs: "https://www.convex.dev/docs",
- },
- tags: ["backend", "database", "api"],
- load: () => import("./convex/index").then((m) => m.generate),
- },
- {
- id: "wikijs",
- name: "Wiki.js",
- version: "2.5",
- description: "The most powerful and extensible open source Wiki software.",
- logo: "wikijs.svg",
- links: {
- github: "https://github.com/requarks/wiki",
- website: "https://js.wiki/",
- docs: "https://docs.requarks.io/",
- },
- tags: ["knowledge-base", "self-hosted", "documentation"],
- load: () => import("./wikijs/index").then((m) => m.generate),
- },
];
diff --git a/apps/dokploy/templates/triggerdotdev/index.ts b/apps/dokploy/templates/triggerdotdev/index.ts
index c11c708b..7b894acb 100644
--- a/apps/dokploy/templates/triggerdotdev/index.ts
+++ b/apps/dokploy/templates/triggerdotdev/index.ts
@@ -1,3 +1,4 @@
+import { Secrets } from "@/components/ui/secrets";
import {
type DomainSchema,
type Schema,
diff --git a/apps/dokploy/templates/trilium/docker-compose.yml b/apps/dokploy/templates/trilium/docker-compose.yml
deleted file mode 100644
index f549d820..00000000
--- a/apps/dokploy/templates/trilium/docker-compose.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-services:
- trilium:
- image: zadam/trilium:latest
- ports:
- - 8080
- networks:
- - dokploy-network
- restart: always
- volumes:
- - /root/trilium-backups:/home/node/trilium-data/backup
-
-networks:
- dokploy-network:
- external: true
diff --git a/apps/dokploy/templates/trilium/index.ts b/apps/dokploy/templates/trilium/index.ts
deleted file mode 100644
index acac9841..00000000
--- a/apps/dokploy/templates/trilium/index.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const triliumDomain = generateRandomDomain(schema);
-
- const domains: DomainSchema[] = [
- {
- host: triliumDomain,
- port: 8080,
- serviceName: "trilium",
- },
- ];
-
- return {
- domains,
- };
-}
diff --git a/apps/dokploy/templates/twenty/docker-compose.yml b/apps/dokploy/templates/twenty/docker-compose.yml
index 800e9a72..34c70aeb 100644
--- a/apps/dokploy/templates/twenty/docker-compose.yml
+++ b/apps/dokploy/templates/twenty/docker-compose.yml
@@ -4,7 +4,8 @@ services:
twenty-change-vol-ownership:
image: ubuntu
user: root
-
+ networks:
+ - dokploy-network
volumes:
- twenty-server-local-data:/tmp/server-local-data
- twenty-docker-data:/tmp/docker-data
@@ -15,7 +16,8 @@ services:
twenty-server:
image: twentycrm/twenty:latest
-
+ networks:
+ - dokploy-network
volumes:
- twenty-server-local-data:/app/packages/twenty-server/${STORAGE_LOCAL_PATH:-.local-storage}
- twenty-docker-data:/app/docker-data
@@ -43,7 +45,8 @@ services:
twenty-worker:
image: twentycrm/twenty:latest
-
+ networks:
+ - dokploy-network
command: ["yarn", "worker:prod"]
environment:
PG_DATABASE_URL: postgres://${DB_USER}:${DB_PASSWORD}@twenty-postgres:5432/twenty
@@ -62,7 +65,8 @@ services:
twenty-postgres:
image: postgres:16-alpine
-
+ networks:
+ - dokploy-network
volumes:
- twenty-postgres-data:/var/lib/postgresql/data
environment:
@@ -78,7 +82,8 @@ services:
twenty-redis:
image: redis:latest
-
+ networks:
+ - dokploy-network
volumes:
- twenty-redis-data:/data
healthcheck:
diff --git a/apps/dokploy/templates/typebot/docker-compose.yml b/apps/dokploy/templates/typebot/docker-compose.yml
index 7881bd8f..739793fe 100644
--- a/apps/dokploy/templates/typebot/docker-compose.yml
+++ b/apps/dokploy/templates/typebot/docker-compose.yml
@@ -13,7 +13,8 @@ services:
POSTGRES_USER: typebot
POSTGRES_DB: typebot
POSTGRES_PASSWORD: typebot
-
+ networks:
+ - dokploy-network
typebot-builder:
image: baptistearno/typebot-builder:2.27
diff --git a/apps/dokploy/templates/umami/docker-compose.yml b/apps/dokploy/templates/umami/docker-compose.yml
index 26efd337..191c4803 100644
--- a/apps/dokploy/templates/umami/docker-compose.yml
+++ b/apps/dokploy/templates/umami/docker-compose.yml
@@ -1,6 +1,6 @@
services:
umami:
- image: ghcr.io/umami-software/umami:postgresql-v2.16.1
+ image: ghcr.io/umami-software/umami:postgresql-v2.14.0
restart: always
healthcheck:
test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]
@@ -22,7 +22,8 @@ services:
interval: 5s
timeout: 5s
retries: 5
-
+ networks:
+ - dokploy-network
volumes:
- db-data:/var/lib/postgresql/data
environment:
diff --git a/apps/dokploy/templates/unifi/docker-compose.yml b/apps/dokploy/templates/unifi/docker-compose.yml
index cf0102c0..ee531f67 100644
--- a/apps/dokploy/templates/unifi/docker-compose.yml
+++ b/apps/dokploy/templates/unifi/docker-compose.yml
@@ -29,7 +29,8 @@ services:
restart: unless-stopped
depends_on:
- unifi-db
-
+ networks:
+ - dokploy-network
unifi-db:
image: mongo:4.4
@@ -39,7 +40,8 @@ services:
ports:
- 27017
restart: unless-stopped
-
+ networks:
+ - dokploy-network
networks:
dokploy-network:
diff --git a/apps/dokploy/templates/unifi/index.ts b/apps/dokploy/templates/unifi/index.ts
index ea67b0fa..975ce63d 100644
--- a/apps/dokploy/templates/unifi/index.ts
+++ b/apps/dokploy/templates/unifi/index.ts
@@ -1,6 +1,6 @@
import type { Schema, Template } from "../utils";
-export function generate(_schema: Schema): Template {
+export function generate(schema: Schema): Template {
const mounts: Template["mounts"] = [
{
filePath: "init-mongo.sh",
diff --git a/apps/dokploy/templates/unsend/docker-compose.yml b/apps/dokploy/templates/unsend/docker-compose.yml
index 93e80295..cdf02de6 100644
--- a/apps/dokploy/templates/unsend/docker-compose.yml
+++ b/apps/dokploy/templates/unsend/docker-compose.yml
@@ -3,7 +3,8 @@ name: unsend-prod
services:
unsend-db-prod:
image: postgres:16
-
+ networks:
+ - dokploy-network
restart: always
environment:
- POSTGRES_USER=${POSTGRES_USER:?err}
@@ -21,7 +22,8 @@ services:
unsend-redis-prod:
image: redis:7
-
+ networks:
+ - dokploy-network
restart: always
# ports:
# - "6379:6379"
@@ -31,7 +33,8 @@ services:
unsend-storage-prod:
image: minio/minio:RELEASE.2024-11-07T00-52-20Z
-
+ networks:
+ - dokploy-network
ports:
- 9002
- 9001
@@ -44,7 +47,9 @@ services:
command: -c 'mkdir -p /data/unsend && minio server /data --console-address ":9001" --address ":9002"'
unsend:
- image: unsend/unsend:v1.3.2
+ image: unsend/unsend:v1.2.4
+ networks:
+ - dokploy-network
restart: always
ports:
- ${PORT:-3000}
diff --git a/apps/dokploy/templates/unsend/index.ts b/apps/dokploy/templates/unsend/index.ts
index dcc80f66..1c4c9c71 100644
--- a/apps/dokploy/templates/unsend/index.ts
+++ b/apps/dokploy/templates/unsend/index.ts
@@ -3,6 +3,7 @@ import {
type Schema,
type Template,
generateBase64,
+ generateHash,
generateRandomDomain,
} from "../utils";
diff --git a/apps/dokploy/templates/utils/index.ts b/apps/dokploy/templates/utils/index.ts
index 941afc80..b5369b91 100644
--- a/apps/dokploy/templates/utils/index.ts
+++ b/apps/dokploy/templates/utils/index.ts
@@ -12,9 +12,7 @@ export interface Schema {
projectName: string;
}
-export type DomainSchema = Pick & {
- path?: string;
-};
+export type DomainSchema = Pick;
export interface Template {
envs?: string[];
diff --git a/apps/dokploy/templates/wikijs/docker-compose.yml b/apps/dokploy/templates/wikijs/docker-compose.yml
deleted file mode 100644
index 6b21423d..00000000
--- a/apps/dokploy/templates/wikijs/docker-compose.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-version: '3.5'
-services:
- wiki:
- image: ghcr.io/requarks/wiki:2.5
- restart: unless-stopped
- environment:
- - DB_TYPE
- - DB_HOST
- - DB_PORT
- - DB_USER
- - DB_PASS
- - DB_NAME
- depends_on:
- - db
- labels:
- - traefik.enable=true
- - traefik.constraint-label-stack=wikijs
- db:
- image: postgres:14
- restart: unless-stopped
- environment:
- - POSTGRES_USER
- - POSTGRES_PASSWORD
- - POSTGRES_DB
- volumes:
- - wiki-db-data:/var/lib/postgresql/data
-networks:
- dokploy-network:
- external: true
-volumes:
- wiki-db-data:
diff --git a/apps/dokploy/templates/wikijs/index.ts b/apps/dokploy/templates/wikijs/index.ts
deleted file mode 100644
index ff6c234d..00000000
--- a/apps/dokploy/templates/wikijs/index.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import {
- type DomainSchema,
- type Schema,
- type Template,
- generateRandomDomain,
-} from "../utils";
-
-export function generate(schema: Schema): Template {
- const domains: DomainSchema[] = [
- {
- host: generateRandomDomain(schema),
- port: 3000,
- serviceName: "wiki",
- },
- ];
-
- const envs = [
- "# Database Setup",
- "POSTGRES_USER=wikijs",
- "POSTGRES_PASSWORD=wikijsrocks",
- "POSTGRES_DB=wiki",
- "# WikiJS Database Connection",
- "DB_TYPE=postgres",
- "DB_HOST=db",
- "DB_PORT=5432",
- "DB_USER=wikijs",
- "DB_PASS=wikijsrocks",
- "DB_NAME=wiki",
- ];
-
- return {
- domains,
- envs,
- };
-}
diff --git a/apps/dokploy/templates/windmill/docker-compose.yml b/apps/dokploy/templates/windmill/docker-compose.yml
index 9e91fa0a..de91ee55 100644
--- a/apps/dokploy/templates/windmill/docker-compose.yml
+++ b/apps/dokploy/templates/windmill/docker-compose.yml
@@ -7,7 +7,8 @@ services:
restart: unless-stopped
volumes:
- windmill-postgres-data:/var/lib/postgresql/data
-
+ networks:
+ - dokploy-network
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: windmill
@@ -19,7 +20,8 @@ services:
windmill-server:
image: ghcr.io/windmill-labs/windmill:main
-
+ networks:
+ - dokploy-network
restart: unless-stopped
environment:
- DATABASE_URL=${DATABASE_URL}
@@ -40,7 +42,8 @@ services:
cpus: "1"
memory: 2048M
restart: unless-stopped
-
+ networks:
+ - dokploy-network
environment:
- DATABASE_URL=${DATABASE_URL}
- MODE=worker
@@ -62,7 +65,8 @@ services:
cpus: "0.1"
memory: 128M
restart: unless-stopped
-
+ networks:
+ - dokploy-network
environment:
- DATABASE_URL=${DATABASE_URL}
- MODE=worker
@@ -78,14 +82,16 @@ services:
windmill-lsp:
image: ghcr.io/windmill-labs/windmill-lsp:latest
restart: unless-stopped
-
+ networks:
+ - dokploy-network
volumes:
- windmill-lsp-cache:/root/.cache
windmill-caddy:
image: ghcr.io/windmill-labs/caddy-l4:latest
restart: unless-stopped
-
+ networks:
+ - dokploy-network
volumes:
- ../files/Caddyfile:/etc/caddy/Caddyfile
environment:
diff --git a/apps/dokploy/templates/wordpress/docker-compose.yml b/apps/dokploy/templates/wordpress/docker-compose.yml
index f2fc4d9a..7647859d 100644
--- a/apps/dokploy/templates/wordpress/docker-compose.yml
+++ b/apps/dokploy/templates/wordpress/docker-compose.yml
@@ -12,6 +12,8 @@ services:
db:
image: mysql:5.7.34
+ networks:
+ - dokploy-network
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
diff --git a/apps/dokploy/templates/yourls/docker-compose.yml b/apps/dokploy/templates/yourls/docker-compose.yml
index f4aa16e3..ff2e14d9 100644
--- a/apps/dokploy/templates/yourls/docker-compose.yml
+++ b/apps/dokploy/templates/yourls/docker-compose.yml
@@ -3,7 +3,8 @@ version: '3.7'
services:
yourls-app:
image: yourls:1.9.2
-
+ networks:
+ - dokploy-network
environment:
YOURLS_SITE: https://${YOURLS_HOST}
YOURLS_USER: ${YOURLS_ADMIN_USER}
@@ -21,7 +22,8 @@ services:
yourls-mysql:
image: mysql:5.7
-
+ networks:
+ - dokploy-network
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: yourls
diff --git a/apps/dokploy/templates/zipline/docker-compose.yml b/apps/dokploy/templates/zipline/docker-compose.yml
index e29132df..808b0b89 100644
--- a/apps/dokploy/templates/zipline/docker-compose.yml
+++ b/apps/dokploy/templates/zipline/docker-compose.yml
@@ -2,7 +2,8 @@ version: "3"
services:
postgres:
image: postgres:15
-
+ networks:
+ - dokploy-network
restart: unless-stopped
environment:
- POSTGRES_USER=postgres
diff --git a/apps/monitoring/.gitignore b/apps/monitoring/.gitignore
deleted file mode 100644
index b3532fce..00000000
--- a/apps/monitoring/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-monitoring.db
\ No newline at end of file
diff --git a/apps/monitoring/LICENSE.md b/apps/monitoring/LICENSE.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/apps/monitoring/README.md b/apps/monitoring/README.md
deleted file mode 100644
index 3d0e1fa6..00000000
--- a/apps/monitoring/README.md
+++ /dev/null
@@ -1,154 +0,0 @@
-# Dokploy Monitoring (Go Version)
-
-Application that powers Dokploy's monitoring service.
-
-You can use it for monitoring any external service.
-
-## Requirements
-
-- Go 1.21
-
-## Configuration
-
-Create a `.env` file in the root of the project with the following content:
-
-```shell
-METRICS_CONFIG='{
- "server": {
- "refreshRate": 25,
- "port": 3001,
- "type": "Remote | Dokploy",
- "token": "metrics",
- "urlCallback": "http://localhost:3000/api/trpc/notification.receiveNotification",
- "retentionDays": 7,
- "cronJob": "0 0 * * *",
- "thresholds": {
- "cpu": 0,
- "memory": 0
- }
- },
- "containers": {
- "refreshRate": 25,
- "services": {
- "include": ["testing-elasticsearch-14649e"],
- "exclude": []
- }
- }
-}'
-```
-
-## Installation
-
-```bash
-go mod download
-```
-
-## Execution
-
-```bash
-go run main.go
-```
-
-## Endpoints
-
-- `GET /health` - Check service health status (no authentication required)
-- `GET /metrics?limit=` - Get server metrics (default limit: 50)
-- `GET /metrics/containers?limit=&appName=` - Get container metrics for a specific application (default limit: 50)
-
-## Features
-
-### Server
-
-- CPU Usage (%)
-- Memory Usage (%)
-- Disk
-- Network
-- CPU Model
-- Operating System
-- Kernel
-- Architecture
-- Threads
-
-Example response:
-
-| Field | Value |
-| ------------------ | --------------------------- |
-| timestamp | 2025-01-19T21:44:54.232164Z |
-| cpu | 24.57% |
-| cpu_model | Apple M1 Pro |
-| cpu_cores | 8 |
-| cpu_physical_cores | 1 |
-| cpu_speed | 3228.0 MHz |
-| os | darwin |
-| distro | darwin |
-| kernel | 23.4.0 |
-| arch | arm64 |
-| mem_used | 81.91% |
-| mem_used_gb | 13.11 GB |
-| mem_total | 16.0 GB |
-| uptime | 752232s |
-| disk_used | 89.34% |
-| total_disk | 460.43 GB |
-| network_in | 54.78 MB |
-| network_out | 31.72 MB |
-
-### Containers
-
-Compatible with all Docker container types (standalone containers, Docker Compose, and Docker Swarm stacks). Note: When monitoring Docker Compose or Swarm stacks, use the `--p` flag to properly identify all services within the stack.
-
-Example response:
-
-| Field | Value |
-| -------------- | ------------------------------------- |
-| id | 1 |
-| timestamp | 2025-01-19T22:16:30.796129Z |
-| container_id | 7428f5a49039 |
-| container_name | testing-elasticsearch-14649e-kibana-1 |
-
-Metrics JSON:
-
-```json
-{
- "timestamp": "2025-01-19T22:16:30.796129Z",
- "CPU": 83.76,
- "Memory": {
- "percentage": 0.03,
- "used": 2.262,
- "total": 7.654,
- "usedUnit": "MB",
- "totalUnit": "GB"
- },
- "Network": {
- "input": 306,
- "output": 0,
- "inputUnit": "B",
- "outputUnit": "B"
- },
- "BlockIO": {
- "read": 28.7,
- "write": 0,
- "readUnit": "kB",
- "writeUnit": "B"
- },
- "Container": "7428f5a49039",
- "ID": "7428f5a49039",
- "Name": "testing-elasticsearch-14649e-kibana-1"
-}
-```
-
-## Notifications
-
-Dokploy uses a callback URL to send notifications when metrics exceed configured thresholds. Notifications are sent via POST request in the following format:
-
-Note: Setting a threshold to 0 disables notifications for that metric.
-
-```typescript
-interface Notification {
- Type: "Memory" | "CPU";
- Value: number;
- Threshold: number;
- Message: string;
- Timestamp: string;
- Token: string;
-}
-```
diff --git a/apps/monitoring/config/metrics.go b/apps/monitoring/config/metrics.go
deleted file mode 100644
index 568b2d06..00000000
--- a/apps/monitoring/config/metrics.go
+++ /dev/null
@@ -1,57 +0,0 @@
-package config
-
-import (
- "encoding/json"
- "log"
- "os"
- "sync"
-)
-
-type Config struct {
- Server struct {
- ServerType string `json:"type"`
- RefreshRate int `json:"refreshRate"`
- Port int `json:"port"`
- Token string `json:"token"`
- UrlCallback string `json:"urlCallback"`
- CronJob string `json:"cronJob"`
- RetentionDays int `json:"retentionDays"`
- Thresholds struct {
- CPU int `json:"cpu"`
- Memory int `json:"memory"`
- } `json:"thresholds"`
- } `json:"server"`
- Containers struct {
- RefreshRate int `json:"refreshRate"`
- Services struct {
- Include []string `json:"include"`
- Exclude []string `json:"exclude"`
- } `json:"services"`
- } `json:"containers"`
-}
-
-var (
- config *Config
- configOnce sync.Once
-)
-
-func GetMetricsConfig() *Config {
- configOnce.Do(func() {
- configJSON := os.Getenv("METRICS_CONFIG")
- if configJSON == "" {
- log.Fatal("METRICS_CONFIG environment variable is required")
- }
-
- config = &Config{}
- if err := json.Unmarshal([]byte(configJSON), config); err != nil {
- log.Fatalf("Error parsing METRICS_CONFIG: %v", err)
- }
-
- // Validate required fields
- if config.Server.Token == "" || config.Server.UrlCallback == "" {
- log.Fatal("token and urlCallback are required in the configuration")
- }
- })
-
- return config
-}
diff --git a/apps/monitoring/containers/config.go b/apps/monitoring/containers/config.go
deleted file mode 100644
index a974bbe3..00000000
--- a/apps/monitoring/containers/config.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package containers
-
-import (
- "strings"
-
- "github.com/mauriciogm/dokploy/apps/monitoring/config"
-)
-
-var monitorConfig *MonitoringConfig
-
-func LoadConfig() error {
- cfg := config.GetMetricsConfig()
- monitorConfig = &MonitoringConfig{
- IncludeServices: make([]string, len(cfg.Containers.Services.Include)),
- ExcludeServices: make([]string, len(cfg.Containers.Services.Exclude)),
- }
-
- // Convert Include services
- for i, svc := range cfg.Containers.Services.Include {
- monitorConfig.IncludeServices[i] = svc
- }
-
- // Convert Exclude services
- for i, appName := range cfg.Containers.Services.Exclude {
- monitorConfig.ExcludeServices[i] = appName
- }
-
- return nil
-}
-
-func ShouldMonitorContainer(containerName string) bool {
- if monitorConfig == nil {
- return false
- }
-
- for _, excluded := range monitorConfig.ExcludeServices {
- if strings.Contains(containerName, excluded) {
- return false
- }
- }
-
- if len(monitorConfig.IncludeServices) > 0 {
- for _, included := range monitorConfig.IncludeServices {
- if strings.Contains(containerName, included) {
- return true
- }
- }
- return false
- }
-
- return true
-}
-
-func GetServiceName(containerName string) string {
- name := strings.TrimPrefix(containerName, "/")
- parts := strings.Split(name, "-")
- if len(parts) > 1 {
- return strings.Join(parts[:len(parts)-1], "-")
- }
- return name
-}
diff --git a/apps/monitoring/containers/monitor.go b/apps/monitoring/containers/monitor.go
deleted file mode 100644
index ff658642..00000000
--- a/apps/monitoring/containers/monitor.go
+++ /dev/null
@@ -1,270 +0,0 @@
-package containers
-
-import (
- "encoding/json"
- "fmt"
- "log"
- "os/exec"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "github.com/mauriciogm/dokploy/apps/monitoring/config"
- "github.com/mauriciogm/dokploy/apps/monitoring/database"
-)
-
-type ContainerMonitor struct {
- db *database.DB
- isRunning bool
- mu sync.Mutex
- stopChan chan struct{}
-}
-
-func NewContainerMonitor(db *database.DB) (*ContainerMonitor, error) {
- if err := db.InitContainerMetricsTable(); err != nil {
- return nil, fmt.Errorf("failed to initialize container metrics table: %v", err)
- }
-
- return &ContainerMonitor{
- db: db,
- stopChan: make(chan struct{}),
- }, nil
-}
-
-func (cm *ContainerMonitor) Start() error {
- if err := LoadConfig(); err != nil {
- return fmt.Errorf("error loading config: %v", err)
- }
-
- // Check if there are services to monitor
- if len(monitorConfig.IncludeServices) == 0 {
- log.Printf("No services to monitor. Skipping container metrics collection")
- return nil
- }
-
- metricsConfig := config.GetMetricsConfig()
- refreshRate := metricsConfig.Containers.RefreshRate
- if refreshRate == 0 {
- refreshRate = 60 // default refresh rate
- }
- duration := time.Duration(refreshRate) * time.Second
-
- // log.Printf("Container metrics collection will run every %d seconds for services: %v", refreshRate, monitorConfig.IncludeServices)
-
- ticker := time.NewTicker(duration)
- go func() {
- for {
- select {
- case <-ticker.C:
- // Check again in case the configuration has changed
- if len(monitorConfig.IncludeServices) == 0 {
- log.Printf("No services to monitor. Stopping metrics collection")
- ticker.Stop()
- return
- }
- cm.collectMetrics()
- case <-cm.stopChan:
- ticker.Stop()
- return
- }
- }
- }()
-
- return nil
-}
-
-func (cm *ContainerMonitor) Stop() {
- close(cm.stopChan)
-}
-
-func (cm *ContainerMonitor) collectMetrics() {
- cm.mu.Lock()
- if cm.isRunning {
- cm.mu.Unlock()
- log.Println("Previous collection still running, skipping...")
- return
- }
- cm.isRunning = true
- cm.mu.Unlock()
-
- defer func() {
- cm.mu.Lock()
- cm.isRunning = false
- cm.mu.Unlock()
- }()
-
- cmd := exec.Command("docker", "stats", "--no-stream", "--format",
- `{"BlockIO":"{{.BlockIO}}","CPUPerc":"{{.CPUPerc}}","ID":"{{.ID}}","MemPerc":"{{.MemPerc}}","MemUsage":"{{.MemUsage}}","Name":"{{.Name}}","NetIO":"{{.NetIO}}"}`)
-
- output, err := cmd.CombinedOutput()
-
- // log.Printf("Output: %s", string(output))
- if err != nil {
- log.Printf("Error getting docker stats: %v", err)
- return
- }
-
- lines := string(output)
- if lines == "" {
- return
- }
-
- seenServices := make(map[string]bool)
- for _, line := range strings.Split(lines, "\n") {
- if line == "" {
- continue
- }
-
- var container Container
- if err := json.Unmarshal([]byte(line), &container); err != nil {
- log.Printf("Error parsing container data: %v", err)
- continue
- }
-
- if !ShouldMonitorContainer(container.Name) {
- continue
- }
-
- serviceName := GetServiceName(container.Name)
-
- if seenServices[serviceName] {
- continue
- }
-
- seenServices[serviceName] = true
-
- // log.Printf("Container: %+v", container)
-
- // Process metrics
- metric := processContainerMetrics(container)
-
- // log.Printf("Saving metrics for %s: %+v", serviceName, metric)
-
- if err := cm.db.SaveContainerMetric(metric); err != nil {
- log.Printf("Error saving metrics for %s: %v", serviceName, err)
- }
- }
-}
-
-func processContainerMetrics(container Container) *database.ContainerMetric {
-
- // Process CPU
- cpu, _ := strconv.ParseFloat(strings.TrimSuffix(container.CPUPerc, "%"), 64)
-
- // Process Memory
- memPerc, _ := strconv.ParseFloat(strings.TrimSuffix(container.MemPerc, "%"), 64)
- memParts := strings.Split(container.MemUsage, " / ")
-
- var usedValue, totalValue float64
- var usedUnit, totalUnit string
-
- if len(memParts) == 2 {
- // Process used memory
- usedParts := strings.Fields(memParts[0])
- if len(usedParts) > 0 {
- usedValue, _ = strconv.ParseFloat(strings.TrimRight(usedParts[0], "MiBGiB"), 64)
- usedUnit = strings.TrimLeft(usedParts[0], "0123456789.")
- // Convert MiB to MB and GiB to GB
- if usedUnit == "MiB" {
- usedUnit = "MB"
- } else if usedUnit == "GiB" {
- usedUnit = "GB"
- }
- }
-
- // Process total memory
- totalParts := strings.Fields(memParts[1])
- if len(totalParts) > 0 {
- totalValue, _ = strconv.ParseFloat(strings.TrimRight(totalParts[0], "MiBGiB"), 64)
- totalUnit = strings.TrimLeft(totalParts[0], "0123456789.")
- // Convert MiB to MB and GiB to GB
- if totalUnit == "MiB" {
- totalUnit = "MB"
- } else if totalUnit == "GiB" {
- totalUnit = "GB"
- }
- }
- }
-
- // Process Network I/O
- netParts := strings.Split(container.NetIO, " / ")
-
- var netInValue, netOutValue float64
- var netInUnit, netOutUnit string
-
- if len(netParts) == 2 {
- // Process input
- inParts := strings.Fields(netParts[0])
- if len(inParts) > 0 {
- netInValue, _ = strconv.ParseFloat(strings.TrimRight(inParts[0], "kMGTB"), 64)
- netInUnit = strings.TrimLeft(inParts[0], "0123456789.")
- }
-
- // Process output
- outParts := strings.Fields(netParts[1])
- if len(outParts) > 0 {
- netOutValue, _ = strconv.ParseFloat(strings.TrimRight(outParts[0], "kMGTB"), 64)
- netOutUnit = strings.TrimLeft(outParts[0], "0123456789.")
- }
- }
-
- // Process Block I/O
- blockParts := strings.Split(container.BlockIO, " / ")
-
- var blockReadValue, blockWriteValue float64
- var blockReadUnit, blockWriteUnit string
-
- if len(blockParts) == 2 {
- // Process read
- readParts := strings.Fields(blockParts[0])
- if len(readParts) > 0 {
- blockReadValue, _ = strconv.ParseFloat(strings.TrimRight(readParts[0], "kMGTB"), 64)
- blockReadUnit = strings.TrimLeft(readParts[0], "0123456789.")
- }
-
- // Process write
- writeParts := strings.Fields(blockParts[1])
- if len(writeParts) > 0 {
- blockWriteValue, _ = strconv.ParseFloat(strings.TrimRight(writeParts[0], "kMGTB"), 64)
- blockWriteUnit = strings.TrimLeft(writeParts[0], "0123456789.")
- }
- }
-
- return &database.ContainerMetric{
- Timestamp: time.Now().UTC().Format(time.RFC3339Nano),
- CPU: cpu,
- Memory: database.MemoryMetric{
- Percentage: memPerc,
- Used: usedValue,
- Total: totalValue,
- UsedUnit: usedUnit,
- TotalUnit: totalUnit,
- },
- Network: database.NetworkMetric{
- Input: netInValue,
- Output: netOutValue,
- InputUnit: netInUnit,
- OutputUnit: netOutUnit,
- },
- BlockIO: database.BlockIOMetric{
- Read: blockReadValue,
- Write: blockWriteValue,
- ReadUnit: blockReadUnit,
- WriteUnit: blockWriteUnit,
- },
- Container: container.ID,
- ID: container.ID,
- Name: container.Name,
- }
-}
-
-func parseValue(value string) (float64, string) {
- parts := strings.Fields(value)
- if len(parts) < 1 {
- return 0, "B"
- }
- v, _ := strconv.ParseFloat(parts[0], 64)
- unit := strings.TrimLeft(value, "0123456789.")
- return v, unit
-}
diff --git a/apps/monitoring/containers/types.go b/apps/monitoring/containers/types.go
deleted file mode 100644
index c1d1c110..00000000
--- a/apps/monitoring/containers/types.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package containers
-
-type Container struct {
- BlockIO string `json:"BlockIO"`
- CPUPerc string `json:"CPUPerc"`
- ID string `json:"ID"`
- MemPerc string `json:"MemPerc"`
- MemUsage string `json:"MemUsage"`
- Name string `json:"Name"`
- NetIO string `json:"NetIO"`
-}
-
-type ContainerMetric struct {
- Timestamp string `json:"timestamp"`
- CPU float64 `json:"CPU"`
- Memory MemoryMetric `json:"Memory"`
- Network NetworkMetric `json:"Network"`
- BlockIO BlockIOMetric `json:"BlockIO"`
- Container string `json:"Container"`
- ID string `json:"ID"`
- Name string `json:"Name"`
-}
-
-type MemoryMetric struct {
- Percentage float64 `json:"percentage"`
- Used float64 `json:"used"`
- Total float64 `json:"total"`
- Unit string `json:"unit"`
-}
-
-type NetworkMetric struct {
- Input float64 `json:"input"`
- Output float64 `json:"output"`
- InputUnit string `json:"inputUnit"`
- OutputUnit string `json:"outputUnit"`
-}
-
-type BlockIOMetric struct {
- Read float64 `json:"read"`
- Write float64 `json:"write"`
- ReadUnit string `json:"readUnit"`
- WriteUnit string `json:"writeUnit"`
-}
-
-type MonitoringConfig struct {
- IncludeServices []string `json:"includeServices"`
- ExcludeServices []string `json:"excludeServices"`
-}
diff --git a/apps/monitoring/database/cleanup.go b/apps/monitoring/database/cleanup.go
deleted file mode 100644
index 9ab0bd26..00000000
--- a/apps/monitoring/database/cleanup.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package database
-
-import (
- "database/sql"
- "log"
- "time"
-
- "github.com/robfig/cron/v3"
-)
-
-// CleanupMetrics deletes metrics older than the retention period
-func CleanupMetrics(db *sql.DB, retentionDays int) error {
- cutoffDate := time.Now().AddDate(0, 0, -retentionDays)
- cutoffDateStr := cutoffDate.UTC().Format(time.RFC3339Nano)
-
- containerQuery := `DELETE FROM container_metrics WHERE timestamp < ?`
- _, err := db.Exec(containerQuery, cutoffDateStr)
- if err != nil {
- return err
- }
-
- serverQuery := `DELETE FROM server_metrics WHERE timestamp < ?`
- _, err = db.Exec(serverQuery, cutoffDateStr)
- if err != nil {
- return err
- }
-
- log.Printf("Metrics deleted (older than %d days)", retentionDays)
- log.Printf("Cutoff date for both tables: %s", cutoffDateStr)
- return nil
-}
-
-// StartMetricsCleanup starts a cron job to periodically clean up metrics
-func StartMetricsCleanup(db *sql.DB, retentionDays int, cronExpression string) (*cron.Cron, error) {
- c := cron.New()
-
- _, err := c.AddFunc(cronExpression, func() {
- if err := CleanupMetrics(db, retentionDays); err != nil {
- log.Printf("Error during metrics cleanup: %v", err)
- }
- })
-
- if err != nil {
- return nil, err
- }
-
- c.Start()
- log.Printf("Started metrics cleanup job (retention: %d days, cron: %s)",
- retentionDays, cronExpression)
-
- return c, nil
-}
diff --git a/apps/monitoring/database/containers.go b/apps/monitoring/database/containers.go
deleted file mode 100644
index 568ad12e..00000000
--- a/apps/monitoring/database/containers.go
+++ /dev/null
@@ -1,160 +0,0 @@
-package database
-
-import (
- "encoding/json"
- "fmt"
- "strings"
-)
-
-func (db *DB) InitContainerMetricsTable() error {
- _, err := db.Exec(`
- CREATE TABLE IF NOT EXISTS container_metrics (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- timestamp TEXT NOT NULL,
- container_id TEXT NOT NULL,
- container_name TEXT NOT NULL,
- metrics_json TEXT NOT NULL
- )
- `)
- if err != nil {
- return fmt.Errorf("error creating container_metrics table: %v", err)
- }
-
- // Crear índices para mejorar el rendimiento
- _, err = db.Exec(`CREATE INDEX IF NOT EXISTS idx_container_metrics_timestamp ON container_metrics(timestamp)`)
- if err != nil {
- return fmt.Errorf("error creating timestamp index: %v", err)
- }
-
- _, err = db.Exec(`CREATE INDEX IF NOT EXISTS idx_container_metrics_name ON container_metrics(container_name)`)
- if err != nil {
- return fmt.Errorf("error creating name index: %v", err)
- }
-
- return nil
-}
-
-func (db *DB) SaveContainerMetric(metric *ContainerMetric) error {
- metricsJSON, err := json.Marshal(metric)
- if err != nil {
- return fmt.Errorf("error marshaling metrics: %v", err)
- }
-
- _, err = db.Exec(`
- INSERT INTO container_metrics (timestamp, container_id, container_name, metrics_json)
- VALUES (?, ?, ?, ?)
- `, metric.Timestamp, metric.ID, metric.Name, string(metricsJSON))
- return err
-}
-
-func (db *DB) GetLastNContainerMetrics(containerName string, limit int) ([]ContainerMetric, error) {
- name := strings.TrimPrefix(containerName, "/")
- parts := strings.Split(name, "-")
- if len(parts) > 1 {
- containerName = strings.Join(parts[:len(parts)-1], "-")
- }
-
- query := `
- WITH recent_metrics AS (
- SELECT metrics_json
- FROM container_metrics
- WHERE container_name LIKE ? || '%'
- ORDER BY timestamp DESC
- LIMIT ?
- )
- SELECT metrics_json FROM recent_metrics ORDER BY json_extract(metrics_json, '$.timestamp') ASC
- `
- rows, err := db.Query(query, containerName, limit)
- if err != nil {
- return nil, err
- }
- defer rows.Close()
-
- var metrics []ContainerMetric
- for rows.Next() {
- var metricsJSON string
- err := rows.Scan(&metricsJSON)
- if err != nil {
- return nil, err
- }
-
- var metric ContainerMetric
- if err := json.Unmarshal([]byte(metricsJSON), &metric); err != nil {
- return nil, err
- }
- metrics = append(metrics, metric)
- }
- return metrics, nil
-}
-
-func (db *DB) GetAllMetricsContainer(containerName string) ([]ContainerMetric, error) {
- name := strings.TrimPrefix(containerName, "/")
- parts := strings.Split(name, "-")
- if len(parts) > 1 {
- containerName = strings.Join(parts[:len(parts)-1], "-")
- }
-
- query := `
- WITH recent_metrics AS (
- SELECT metrics_json
- FROM container_metrics
- WHERE container_name LIKE ? || '%'
- ORDER BY timestamp DESC
- )
- SELECT metrics_json FROM recent_metrics ORDER BY json_extract(metrics_json, '$.timestamp') ASC
- `
- rows, err := db.Query(query, containerName)
- if err != nil {
- return nil, err
- }
- defer rows.Close()
-
- var metrics []ContainerMetric
- for rows.Next() {
- var metricsJSON string
- err := rows.Scan(&metricsJSON)
- if err != nil {
- return nil, err
- }
-
- var metric ContainerMetric
- if err := json.Unmarshal([]byte(metricsJSON), &metric); err != nil {
- return nil, err
- }
- metrics = append(metrics, metric)
- }
- return metrics, nil
-}
-
-type ContainerMetric struct {
- Timestamp string `json:"timestamp"`
- CPU float64 `json:"CPU"`
- Memory MemoryMetric `json:"Memory"`
- Network NetworkMetric `json:"Network"`
- BlockIO BlockIOMetric `json:"BlockIO"`
- Container string `json:"Container"`
- ID string `json:"ID"`
- Name string `json:"Name"`
-}
-
-type MemoryMetric struct {
- Percentage float64 `json:"percentage"`
- Used float64 `json:"used"`
- Total float64 `json:"total"`
- UsedUnit string `json:"usedUnit"`
- TotalUnit string `json:"totalUnit"`
-}
-
-type NetworkMetric struct {
- Input float64 `json:"input"`
- Output float64 `json:"output"`
- InputUnit string `json:"inputUnit"`
- OutputUnit string `json:"outputUnit"`
-}
-
-type BlockIOMetric struct {
- Read float64 `json:"read"`
- Write float64 `json:"write"`
- ReadUnit string `json:"readUnit"`
- WriteUnit string `json:"writeUnit"`
-}
diff --git a/apps/monitoring/database/db.go b/apps/monitoring/database/db.go
deleted file mode 100644
index 689564fc..00000000
--- a/apps/monitoring/database/db.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package database
-
-import (
- "database/sql"
-
- _ "github.com/mattn/go-sqlite3"
-)
-
-type DB struct {
- *sql.DB
-}
-
-func InitDB() (*DB, error) {
- db, err := sql.Open("sqlite3", "./monitoring.db")
- if err != nil {
- return nil, err
- }
-
- // Create metrics table if it doesn't exist
- _, err = db.Exec(`
- CREATE TABLE IF NOT EXISTS server_metrics (
- timestamp TEXT PRIMARY KEY,
- cpu REAL,
- cpu_model TEXT,
- cpu_cores INTEGER,
- cpu_physical_cores INTEGER,
- cpu_speed REAL,
- os TEXT,
- distro TEXT,
- kernel TEXT,
- arch TEXT,
- mem_used REAL,
- mem_used_gb REAL,
- mem_total REAL,
- uptime INTEGER,
- disk_used REAL,
- total_disk REAL,
- network_in REAL,
- network_out REAL
- )
- `)
- if err != nil {
- return nil, err
- }
-
- return &DB{db}, nil
-}
diff --git a/apps/monitoring/database/server.go b/apps/monitoring/database/server.go
deleted file mode 100644
index 64d22e3d..00000000
--- a/apps/monitoring/database/server.go
+++ /dev/null
@@ -1,115 +0,0 @@
-package database
-
-import (
- "time"
-
- _ "github.com/mattn/go-sqlite3"
-)
-
-type ServerMetric struct {
- Timestamp string `json:"timestamp"`
- CPU float64 `json:"cpu"`
- CPUModel string `json:"cpuModel"`
- CPUCores int32 `json:"cpuCores"`
- CPUPhysicalCores int32 `json:"cpuPhysicalCores"`
- CPUSpeed float64 `json:"cpuSpeed"`
- OS string `json:"os"`
- Distro string `json:"distro"`
- Kernel string `json:"kernel"`
- Arch string `json:"arch"`
- MemUsed float64 `json:"memUsed"`
- MemUsedGB float64 `json:"memUsedGB"`
- MemTotal float64 `json:"memTotal"`
- Uptime uint64 `json:"uptime"`
- DiskUsed float64 `json:"diskUsed"`
- TotalDisk float64 `json:"totalDisk"`
- NetworkIn float64 `json:"networkIn"`
- NetworkOut float64 `json:"networkOut"`
-}
-
-func (db *DB) SaveMetric(metric ServerMetric) error {
- if metric.Timestamp == "" {
- metric.Timestamp = time.Now().UTC().Format(time.RFC3339Nano)
- }
-
- _, err := db.Exec(`
- INSERT INTO server_metrics (timestamp, cpu, cpu_model, cpu_cores, cpu_physical_cores, cpu_speed, os, distro, kernel, arch, mem_used, mem_used_gb, mem_total, uptime, disk_used, total_disk, network_in, network_out)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- `, metric.Timestamp, metric.CPU, metric.CPUModel, metric.CPUCores, metric.CPUPhysicalCores, metric.CPUSpeed, metric.OS, metric.Distro, metric.Kernel, metric.Arch, metric.MemUsed, metric.MemUsedGB, metric.MemTotal, metric.Uptime, metric.DiskUsed, metric.TotalDisk, metric.NetworkIn, metric.NetworkOut)
- return err
-}
-
-func (db *DB) GetMetricsInRange(start, end time.Time) ([]ServerMetric, error) {
- rows, err := db.Query(`
- SELECT timestamp, cpu, cpu_model, cpu_cores, cpu_physical_cores, cpu_speed, os, distro, kernel, arch, mem_used, mem_used_gb, mem_total, uptime, disk_used, total_disk, network_in, network_out
- FROM server_metrics
- WHERE timestamp BETWEEN ? AND ?
- ORDER BY timestamp ASC
- `, start.UTC().Format(time.RFC3339Nano), end.UTC().Format(time.RFC3339Nano))
- if err != nil {
- return nil, err
- }
- defer rows.Close()
-
- var metrics []ServerMetric
- for rows.Next() {
- var m ServerMetric
- err := rows.Scan(&m.Timestamp, &m.CPU, &m.CPUModel, &m.CPUCores, &m.CPUPhysicalCores, &m.CPUSpeed, &m.OS, &m.Distro, &m.Kernel, &m.Arch, &m.MemUsed, &m.MemUsedGB, &m.MemTotal, &m.Uptime, &m.DiskUsed, &m.TotalDisk, &m.NetworkIn, &m.NetworkOut)
- if err != nil {
- return nil, err
- }
- metrics = append(metrics, m)
- }
- return metrics, nil
-}
-
-func (db *DB) GetLastNMetrics(n int) ([]ServerMetric, error) {
- rows, err := db.Query(`
- WITH recent_metrics AS (
- SELECT timestamp, cpu, cpu_model, cpu_cores, cpu_physical_cores, cpu_speed, os, distro, kernel, arch, mem_used, mem_used_gb, mem_total, uptime, disk_used, total_disk, network_in, network_out
- FROM server_metrics
- ORDER BY timestamp DESC
- LIMIT ?
- )
- SELECT * FROM recent_metrics
- ORDER BY timestamp ASC
- `, n)
- if err != nil {
- return nil, err
- }
- defer rows.Close()
-
- var metrics []ServerMetric
- for rows.Next() {
- var m ServerMetric
- err := rows.Scan(&m.Timestamp, &m.CPU, &m.CPUModel, &m.CPUCores, &m.CPUPhysicalCores, &m.CPUSpeed, &m.OS, &m.Distro, &m.Kernel, &m.Arch, &m.MemUsed, &m.MemUsedGB, &m.MemTotal, &m.Uptime, &m.DiskUsed, &m.TotalDisk, &m.NetworkIn, &m.NetworkOut)
- if err != nil {
- return nil, err
- }
- metrics = append(metrics, m)
- }
- return metrics, nil
-}
-
-func (db *DB) GetAllMetrics() ([]ServerMetric, error) {
- rows, err := db.Query(`
- SELECT timestamp, cpu, cpu_model, cpu_cores, cpu_physical_cores, cpu_speed, os, distro, kernel, arch, mem_used, mem_used_gb, mem_total, uptime, disk_used, total_disk, network_in, network_out
- FROM server_metrics
- ORDER BY timestamp ASC
- `)
- if err != nil {
- return nil, err
- }
- defer rows.Close()
-
- var metrics []ServerMetric
- for rows.Next() {
- var m ServerMetric
- err := rows.Scan(&m.Timestamp, &m.CPU, &m.CPUModel, &m.CPUCores, &m.CPUPhysicalCores, &m.CPUSpeed, &m.OS, &m.Distro, &m.Kernel, &m.Arch, &m.MemUsed, &m.MemUsedGB, &m.MemTotal, &m.Uptime, &m.DiskUsed, &m.TotalDisk, &m.NetworkIn, &m.NetworkOut)
- if err != nil {
- return nil, err
- }
- metrics = append(metrics, m)
- }
- return metrics, nil
-}
diff --git a/apps/monitoring/go.mod b/apps/monitoring/go.mod
deleted file mode 100644
index 2c1590b4..00000000
--- a/apps/monitoring/go.mod
+++ /dev/null
@@ -1,34 +0,0 @@
-module github.com/mauriciogm/dokploy/apps/monitoring
-
-go 1.20
-
-require (
- github.com/gofiber/fiber/v2 v2.52.6
- github.com/joho/godotenv v1.5.1
- github.com/mattn/go-sqlite3 v1.14.24
- github.com/shirou/gopsutil/v3 v3.24.5
-)
-
-require (
- github.com/andybalholm/brotli v1.1.0 // indirect
- github.com/go-ole/go-ole v1.2.6 // indirect
- github.com/google/uuid v1.6.0 // indirect
- github.com/klauspost/compress v1.17.9 // indirect
- github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mattn/go-runewidth v0.0.16 // indirect
- github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
- github.com/rivo/uniseg v0.2.0 // indirect
- github.com/robfig/cron/v3 v3.0.1 // indirect
- github.com/shoenig/go-m1cpu v0.1.6 // indirect
- github.com/tklauser/go-sysconf v0.3.14 // indirect
- github.com/tklauser/numcpus v0.8.0 // indirect
- github.com/valyala/bytebufferpool v1.0.0 // indirect
- github.com/valyala/fasthttp v1.51.0 // indirect
- github.com/valyala/tcplisten v1.0.0 // indirect
- github.com/yusufpapurcu/wmi v1.2.4 // indirect
- golang.org/x/sys v0.28.0 // indirect
-)
-
-replace github.com/mauriciogm/dokploy/apps/monitoring => ./
diff --git a/apps/monitoring/go.sum b/apps/monitoring/go.sum
deleted file mode 100644
index 7a4c9db8..00000000
--- a/apps/monitoring/go.sum
+++ /dev/null
@@ -1,61 +0,0 @@
-github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
-github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
-github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI=
-github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
-github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
-github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
-github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
-github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
-github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
-github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
-github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
-github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
-github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
-github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
-github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
-github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
-github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
-github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
-github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
-github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
-github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
-github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
-github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
-github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
-github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
-github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
-github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
-github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
-github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
-github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
-github.com/zcalusic/sysinfo v1.1.3 h1:u/AVENkuoikKuIZ4sUEJ6iibpmQP6YpGD8SSMCrqAF0=
-github.com/zcalusic/sysinfo v1.1.3/go.mod h1:NX+qYnWGtJVPV0yWldff9uppNKU4h40hJIRPf/pGLv4=
-golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
-golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/apps/monitoring/main.go b/apps/monitoring/main.go
deleted file mode 100644
index 432ccd24..00000000
--- a/apps/monitoring/main.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package main
-
-import (
- "log"
- "os"
- "strconv"
- "time"
-
- "github.com/gofiber/fiber/v2"
- "github.com/gofiber/fiber/v2/middleware/cors"
- "github.com/joho/godotenv"
- "github.com/mauriciogm/dokploy/apps/monitoring/config"
- "github.com/mauriciogm/dokploy/apps/monitoring/containers"
- "github.com/mauriciogm/dokploy/apps/monitoring/database"
- "github.com/mauriciogm/dokploy/apps/monitoring/middleware"
- "github.com/mauriciogm/dokploy/apps/monitoring/monitoring"
-)
-
-func main() {
- godotenv.Load()
-
- // Get configuration
- cfg := config.GetMetricsConfig()
- token := cfg.Server.Token
- METRICS_URL_CALLBACK := cfg.Server.UrlCallback
- log.Printf("Environment variables:")
- log.Printf("METRICS_CONFIG: %s", os.Getenv("METRICS_CONFIG"))
-
- if token == "" || METRICS_URL_CALLBACK == "" {
- log.Fatal("token and urlCallback are required in the configuration")
- }
-
- db, err := database.InitDB()
- if err != nil {
- log.Fatal(err)
- }
-
- // Iniciar el sistema de limpieza de métricas
- cleanupCron, err := database.StartMetricsCleanup(db.DB, cfg.Server.RetentionDays, cfg.Server.CronJob)
- if err != nil {
- log.Fatalf("Error starting metrics cleanup system: %v", err)
- }
- defer cleanupCron.Stop()
-
- app := fiber.New()
-
- app.Use(cors.New(cors.Config{
- AllowOrigins: "*",
- AllowHeaders: "Origin, Content-Type, Accept, Authorization",
- }))
-
- app.Get("/health", func(c *fiber.Ctx) error {
- return c.JSON(fiber.Map{
- "status": "ok",
- })
- })
-
- app.Use(func(c *fiber.Ctx) error {
- if c.Path() == "/health" {
- return c.Next()
- }
- return middleware.AuthMiddleware()(c)
- })
-
- app.Get("/metrics", func(c *fiber.Ctx) error {
- limit := c.Query("limit", "50")
-
- var metrics []monitoring.SystemMetrics
- if limit == "all" {
- dbMetrics, err := db.GetAllMetrics()
- if err != nil {
- return c.Status(500).JSON(fiber.Map{
- "error": "Failed to fetch metrics",
- })
- }
- for _, m := range dbMetrics {
- metrics = append(metrics, monitoring.ConvertToSystemMetrics(m))
- }
- } else {
- n, err := strconv.Atoi(limit)
- if err != nil {
- n = 50
- }
- dbMetrics, err := db.GetLastNMetrics(n)
- if err != nil {
- return c.Status(500).JSON(fiber.Map{
- "error": "Failed to fetch metrics",
- })
- }
- for _, m := range dbMetrics {
- metrics = append(metrics, monitoring.ConvertToSystemMetrics(m))
- }
- }
-
- return c.JSON(metrics)
- })
-
- containerMonitor, err := containers.NewContainerMonitor(db)
- if err != nil {
- log.Fatalf("Failed to create container monitor: %v", err)
- }
- if err := containerMonitor.Start(); err != nil {
- log.Fatalf("Failed to start container monitor: %v", err)
- }
- defer containerMonitor.Stop()
-
- app.Get("/metrics/containers", func(c *fiber.Ctx) error {
- limit := c.Query("limit", "50")
- appName := c.Query("appName", "")
-
- if appName == "" {
- return c.JSON([]database.ContainerMetric{})
- }
-
- var metrics []database.ContainerMetric
- var err error
-
- if limit == "all" {
- metrics, err = db.GetAllMetricsContainer(appName)
- } else {
- limitNum, parseErr := strconv.Atoi(limit)
- if parseErr != nil {
- limitNum = 50
- }
- metrics, err = db.GetLastNContainerMetrics(appName, limitNum)
- }
-
- if err != nil {
- return c.Status(500).JSON(fiber.Map{
- "error": "Error getting container metrics: " + err.Error(),
- })
- }
-
- return c.JSON(metrics)
- })
-
- go func() {
- refreshRate := cfg.Server.RefreshRate
- duration := time.Duration(refreshRate) * time.Second
-
- log.Printf("Refreshing server metrics every %v", duration)
- ticker := time.NewTicker(duration)
- defer ticker.Stop()
-
- for range ticker.C {
- metrics := monitoring.GetServerMetrics()
- if err := db.SaveMetric(metrics); err != nil {
- log.Printf("Error saving metrics: %v", err)
- }
-
- if err := monitoring.CheckThresholds(metrics); err != nil {
- log.Printf("Error checking thresholds: %v", err)
- }
- }
- }()
-
- port := cfg.Server.Port
- if port == 0 {
- port = 3001
- }
-
- log.Printf("Server starting on port %d", port)
- log.Fatal(app.Listen(":" + strconv.Itoa(port)))
-}
diff --git a/apps/monitoring/middleware/auth.go b/apps/monitoring/middleware/auth.go
deleted file mode 100644
index 95448213..00000000
--- a/apps/monitoring/middleware/auth.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package middleware
-
-import (
- "strings"
-
- "github.com/gofiber/fiber/v2"
- "github.com/mauriciogm/dokploy/apps/monitoring/config"
-)
-
-func AuthMiddleware() fiber.Handler {
- return func(c *fiber.Ctx) error {
- expectedToken := config.GetMetricsConfig().Server.Token
-
- authHeader := c.Get("Authorization")
- if authHeader == "" {
- return c.Status(401).JSON(fiber.Map{
- "error": "Authorization header is required",
- })
- }
-
- // Check if the header starts with "Bearer "
- if !strings.HasPrefix(authHeader, "Bearer ") {
- return c.Status(401).JSON(fiber.Map{
- "error": "Invalid authorization format. Use 'Bearer TOKEN'",
- })
- }
-
- // Extract the token
- token := strings.TrimPrefix(authHeader, "Bearer ")
-
- if token != expectedToken {
- return c.Status(401).JSON(fiber.Map{
- "error": "Invalid token",
- })
- }
-
- return c.Next()
- }
-}
diff --git a/apps/monitoring/monitoring/monitor.go b/apps/monitoring/monitoring/monitor.go
deleted file mode 100644
index 0beb4320..00000000
--- a/apps/monitoring/monitoring/monitor.go
+++ /dev/null
@@ -1,261 +0,0 @@
-package monitoring
-
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "os"
- "os/exec"
- "runtime"
- "strings"
- "time"
-
- "github.com/shirou/gopsutil/v3/cpu"
- "github.com/shirou/gopsutil/v3/disk"
- "github.com/shirou/gopsutil/v3/host"
- "github.com/shirou/gopsutil/v3/mem"
- "github.com/shirou/gopsutil/v3/net"
-
- "github.com/mauriciogm/dokploy/apps/monitoring/config"
- "github.com/mauriciogm/dokploy/apps/monitoring/database"
-)
-
-type SystemMetrics struct {
- CPU string `json:"cpu"`
- CPUModel string `json:"cpuModel"`
- CPUCores int32 `json:"cpuCores"`
- CPUPhysicalCores int32 `json:"cpuPhysicalCores"`
- CPUSpeed float64 `json:"cpuSpeed"`
- OS string `json:"os"`
- Distro string `json:"distro"`
- Kernel string `json:"kernel"`
- Arch string `json:"arch"`
- MemUsed string `json:"memUsed"`
- MemUsedGB string `json:"memUsedGB"`
- MemTotal string `json:"memTotal"`
- Uptime uint64 `json:"uptime"`
- DiskUsed string `json:"diskUsed"`
- TotalDisk string `json:"totalDisk"`
- NetworkIn string `json:"networkIn"`
- NetworkOut string `json:"networkOut"`
- Timestamp string `json:"timestamp"`
-}
-
-type AlertPayload struct {
- ServerType string `json:"ServerType"`
- Type string `json:"Type"`
- Value float64 `json:"Value"`
- Threshold float64 `json:"Threshold"`
- Message string `json:"Message"`
- Timestamp string `json:"Timestamp"`
- Token string `json:"Token"`
-}
-
-func getRealOS() string {
- if content, err := os.ReadFile("/etc/os-release"); err == nil {
- lines := strings.Split(string(content), "\n")
- var id, name, version string
- for _, line := range lines {
- if strings.HasPrefix(line, "PRETTY_NAME=") {
- return strings.Trim(strings.TrimPrefix(line, "PRETTY_NAME="), "\"")
- } else if strings.HasPrefix(line, "NAME=") {
- name = strings.Trim(strings.TrimPrefix(line, "NAME="), "\"")
- } else if strings.HasPrefix(line, "VERSION=") {
- version = strings.Trim(strings.TrimPrefix(line, "VERSION="), "\"")
- } else if strings.HasPrefix(line, "ID=") {
- id = strings.Trim(strings.TrimPrefix(line, "ID="), "\"")
- }
- }
- if name != "" && version != "" {
- return fmt.Sprintf("%s %s", name, version)
- }
- if name != "" {
- return name
- }
- if id != "" {
- return id
- }
- }
-
- if content, err := os.ReadFile("/etc/system-release"); err == nil {
- text := strings.ToLower(string(content))
- switch {
- case strings.Contains(text, "red hat"):
- return "rhel"
- case strings.Contains(text, "centos"):
- return "centos"
- case strings.Contains(text, "fedora"):
- return "fedora"
- }
- }
-
- cmd := exec.Command("uname", "-a")
- if output, err := cmd.Output(); err == nil {
- osInfo := strings.ToLower(string(output))
- switch {
- case strings.Contains(osInfo, "debian"):
- return "debian"
- case strings.Contains(osInfo, "ubuntu"):
- return "ubuntu"
- case strings.Contains(osInfo, "centos"):
- return "centos"
- case strings.Contains(osInfo, "fedora"):
- return "fedora"
- case strings.Contains(osInfo, "red hat"):
- return "rhel"
- case strings.Contains(osInfo, "arch"):
- return "arch"
- case strings.Contains(osInfo, "darwin"):
- return "darwin"
- }
- }
-
- return runtime.GOOS
-}
-
-func GetServerMetrics() database.ServerMetric {
- v, _ := mem.VirtualMemory()
- c, _ := cpu.Percent(0, false)
- cpuInfo, _ := cpu.Info()
- diskInfo, _ := disk.Usage("/")
- netInfo, _ := net.IOCounters(false)
- hostInfo, _ := host.Info()
- distro := getRealOS()
-
- cpuModel := ""
- if len(cpuInfo) > 0 {
- cpuModel = fmt.Sprintf("%s %s", cpuInfo[0].VendorID, cpuInfo[0].ModelName)
- }
-
- memTotalGB := float64(v.Total) / 1024 / 1024 / 1024
- memUsedGB := float64(v.Used) / 1024 / 1024 / 1024
- memUsedPercent := (memUsedGB / memTotalGB) * 100
-
- var networkIn, networkOut float64
- if len(netInfo) > 0 {
- networkIn = float64(netInfo[0].BytesRecv) / 1024 / 1024
- networkOut = float64(netInfo[0].BytesSent) / 1024 / 1024
- }
- return database.ServerMetric{
- Timestamp: time.Now().UTC().Format(time.RFC3339Nano),
- CPU: c[0],
- CPUModel: cpuModel,
- CPUCores: int32(runtime.NumCPU()),
- CPUPhysicalCores: int32(len(cpuInfo)),
- CPUSpeed: float64(cpuInfo[0].Mhz),
- OS: getRealOS(),
- Distro: distro,
- Kernel: hostInfo.KernelVersion,
- Arch: hostInfo.KernelArch,
- MemUsed: memUsedPercent,
- MemUsedGB: memUsedGB,
- MemTotal: memTotalGB,
- Uptime: hostInfo.Uptime,
- DiskUsed: float64(diskInfo.UsedPercent),
- TotalDisk: float64(diskInfo.Total) / 1024 / 1024 / 1024,
- NetworkIn: networkIn,
- NetworkOut: networkOut,
- }
-}
-
-func ConvertToSystemMetrics(metric database.ServerMetric) SystemMetrics {
- return SystemMetrics{
- CPU: fmt.Sprintf("%.2f", metric.CPU),
- CPUModel: metric.CPUModel,
- CPUCores: metric.CPUCores,
- CPUPhysicalCores: metric.CPUPhysicalCores,
- CPUSpeed: metric.CPUSpeed,
- OS: metric.OS,
- Distro: metric.Distro,
- Kernel: metric.Kernel,
- Arch: metric.Arch,
- MemUsed: fmt.Sprintf("%.2f", metric.MemUsed),
- MemUsedGB: fmt.Sprintf("%.2f", metric.MemUsedGB),
- MemTotal: fmt.Sprintf("%.2f", metric.MemTotal),
- Uptime: metric.Uptime,
- DiskUsed: fmt.Sprintf("%.2f", metric.DiskUsed),
- TotalDisk: fmt.Sprintf("%.2f", metric.TotalDisk),
- NetworkIn: fmt.Sprintf("%.2f", metric.NetworkIn),
- NetworkOut: fmt.Sprintf("%.2f", metric.NetworkOut),
- Timestamp: metric.Timestamp,
- }
-}
-
-func CheckThresholds(metrics database.ServerMetric) error {
- cfg := config.GetMetricsConfig()
- cpuThreshold := float64(cfg.Server.Thresholds.CPU)
- memThreshold := float64(cfg.Server.Thresholds.Memory)
- callbackURL := cfg.Server.UrlCallback
- metricsToken := cfg.Server.Token
-
- // log.Printf("CPU threshold: %.2f%%", cpuThreshold)
- // log.Printf("Current CPU usage: %.2f%%", metrics.CPU)
- // log.Printf("Memory threshold: %.2f%%", memThreshold)
- // log.Printf("Callback URL: %s", callbackURL)
- // log.Printf("Metrics token: %s", metricsToken)
-
- if cpuThreshold == 0 && memThreshold == 0 {
- return nil
- }
-
- if cpuThreshold > 0 && metrics.CPU > cpuThreshold {
- alert := AlertPayload{
- ServerType: cfg.Server.ServerType,
- Type: "CPU",
- Value: metrics.CPU,
- Threshold: cpuThreshold,
- Message: fmt.Sprintf("CPU usage (%.2f%%) exceeded threshold (%.2f%%)", metrics.CPU, cpuThreshold),
- Timestamp: metrics.Timestamp,
- Token: metricsToken,
- }
- if err := sendAlert(callbackURL, alert); err != nil {
- return fmt.Errorf("failed to send CPU alert: %v", err)
- }
- }
-
- if memThreshold > 0 && metrics.MemUsed > memThreshold {
- alert := AlertPayload{
- ServerType: cfg.Server.ServerType,
- Type: "Memory",
- Value: metrics.MemUsed,
- Threshold: memThreshold,
- Message: fmt.Sprintf("Memory usage (%.2f%%) exceeded threshold (%.2f%%)", metrics.MemUsed, memThreshold),
- Timestamp: metrics.Timestamp,
- Token: metricsToken,
- }
- if err := sendAlert(callbackURL, alert); err != nil {
- return fmt.Errorf("failed to send memory alert: %v", err)
- }
- }
-
- return nil
-}
-
-func sendAlert(callbackURL string, payload AlertPayload) error {
- if callbackURL == "" {
- return fmt.Errorf("callback URL is not set")
- }
- wrappedPayload := map[string]interface{}{
- "json": payload,
- }
-
- jsonData, err := json.Marshal(wrappedPayload)
- if err != nil {
- return fmt.Errorf("failed to marshal alert payload: %v", err)
- }
-
- resp, err := http.Post(callbackURL, "application/json", bytes.NewBuffer(jsonData))
- if err != nil {
- return fmt.Errorf("failed to send POST request: %v", err)
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- bodyBytes, _ := io.ReadAll(resp.Body)
- return fmt.Errorf("received non-OK response status: %s, body: %s", resp.Status, string(bodyBytes))
- }
-
- return nil
-}
diff --git a/apps/schedules/package.json b/apps/schedules/package.json
index 0a869fb0..dd6818d1 100644
--- a/apps/schedules/package.json
+++ b/apps/schedules/package.json
@@ -8,7 +8,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
- "drizzle-orm": "^0.39.1",
+ "drizzle-orm": "^0.30.8",
"ioredis": "5.4.1",
"bullmq": "5.4.2",
"@hono/zod-validator": "0.3.0",
diff --git a/apps/schedules/tsconfig.json b/apps/schedules/tsconfig.json
index 3d4adb16..3c0b02bc 100644
--- a/apps/schedules/tsconfig.json
+++ b/apps/schedules/tsconfig.json
@@ -7,8 +7,7 @@
"skipLibCheck": true,
"outDir": "dist",
"jsx": "react-jsx",
- "jsxImportSource": "hono/jsx",
- "declaration": false
+ "jsxImportSource": "hono/jsx"
},
"exclude": ["node_modules", "dist"]
}
diff --git a/biome.json b/biome.json
index cf677ec4..f5a6c232 100644
--- a/biome.json
+++ b/biome.json
@@ -24,10 +24,7 @@
},
"correctness": {
"useExhaustiveDependencies": "off",
- "noUnsafeOptionalChaining": "off",
- "noUnusedImports": "error",
- "noUnusedFunctionParameters": "error",
- "noUnusedVariables": "error"
+ "noUnsafeOptionalChaining": "off"
},
"style": {
"noNonNullAssertion": "off"
diff --git a/lefthook.yml b/lefthook.yml
index 3f5a6d09..1a491cd8 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -37,9 +37,9 @@
commit-msg:
commands:
commitlint:
- # run: "npx commitlint --edit $1"
+ run: "npx commitlint --edit $1"
pre-commit:
commands:
check:
- # run: "pnpm check"
+ run: "pnpm check"
diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts
deleted file mode 100644
index a5829046..00000000
--- a/packages/server/auth-schema.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-// import {
-// pgTable,
-// text,
-// integer,
-// timestamp,
-// boolean,
-// } from "drizzle-orm/pg-core";
-
-// export const users_temp = pgTable("users_temp", {
-// id: text("id").primaryKey(),
-// name: text("name").notNull(),
-// email: text("email").notNull().unique(),
-// emailVerified: boolean("email_verified").notNull(),
-// image: text("image"),
-// createdAt: timestamp("created_at").notNull(),
-// updatedAt: timestamp("updated_at").notNull(),
-// twoFactorEnabled: boolean("two_factor_enabled"),
-// role: text("role"),
-// ownerId: text("owner_id"),
-// });
-
-// export const session = pgTable("session", {
-// id: text("id").primaryKey(),
-// expiresAt: timestamp("expires_at").notNull(),
-// token: text("token").notNull().unique(),
-// createdAt: timestamp("created_at").notNull(),
-// updatedAt: timestamp("updated_at").notNull(),
-// ipAddress: text("ip_address"),
-// userAgent: text("user_agent"),
-// userId: text("user_id")
-// .notNull()
-// .references(() => users_temp.id, { onDelete: "cascade" }),
-// activeOrganizationId: text("active_organization_id"),
-// });
-
-// export const account = pgTable("account", {
-// id: text("id").primaryKey(),
-// accountId: text("account_id").notNull(),
-// providerId: text("provider_id").notNull(),
-// userId: text("user_id")
-// .notNull()
-// .references(() => users_temp.id, { onDelete: "cascade" }),
-// accessToken: text("access_token"),
-// refreshToken: text("refresh_token"),
-// idToken: text("id_token"),
-// accessTokenExpiresAt: timestamp("access_token_expires_at"),
-// refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
-// scope: text("scope"),
-// password: text("password"),
-// createdAt: timestamp("created_at").notNull(),
-// updatedAt: timestamp("updated_at").notNull(),
-// });
-
-// export const verification = pgTable("verification", {
-// id: text("id").primaryKey(),
-// identifier: text("identifier").notNull(),
-// value: text("value").notNull(),
-// expiresAt: timestamp("expires_at").notNull(),
-// createdAt: timestamp("created_at"),
-// updatedAt: timestamp("updated_at"),
-// });
-
-// export const apikey = pgTable("apikey", {
-// id: text("id").primaryKey(),
-// name: text("name"),
-// start: text("start"),
-// prefix: text("prefix"),
-// key: text("key").notNull(),
-// userId: text("user_id")
-// .notNull()
-// .references(() => user.id, { onDelete: "cascade" }),
-// refillInterval: integer("refill_interval"),
-// refillAmount: integer("refill_amount"),
-// lastRefillAt: timestamp("last_refill_at"),
-// enabled: boolean("enabled"),
-// rateLimitEnabled: boolean("rate_limit_enabled"),
-// rateLimitTimeWindow: integer("rate_limit_time_window"),
-// rateLimitMax: integer("rate_limit_max"),
-// requestCount: integer("request_count"),
-// remaining: integer("remaining"),
-// lastRequest: timestamp("last_request"),
-// expiresAt: timestamp("expires_at"),
-// createdAt: timestamp("created_at").notNull(),
-// updatedAt: timestamp("updated_at").notNull(),
-// permissions: text("permissions"),
-// metadata: text("metadata"),
-// });
-
-// export const twoFactor = pgTable("two_factor", {
-// id: text("id").primaryKey(),
-// secret: text("secret").notNull(),
-// backupCodes: text("backup_codes").notNull(),
-// userId: text("user_id")
-// .notNull()
-// .references(() => user.id, { onDelete: "cascade" }),
-// });
-
-// export const organization = pgTable("organization", {
-// id: text("id").primaryKey(),
-// name: text("name").notNull(),
-// slug: text("slug").unique(),
-// logo: text("logo"),
-// createdAt: timestamp("created_at").notNull(),
-// metadata: text("metadata"),
-// });
-
-// export const member = pgTable("member", {
-// id: text("id").primaryKey(),
-// organizationId: text("organization_id")
-// .notNull()
-// .references(() => organization.id, { onDelete: "cascade" }),
-// userId: text("user_id")
-// .notNull()
-// .references(() => user.id, { onDelete: "cascade" }),
-// role: text("role").notNull(),
-// teamId: text("team_id"),
-// createdAt: timestamp("created_at").notNull(),
-// });
-
-// export const invitation = pgTable("invitation", {
-// id: text("id").primaryKey(),
-// organizationId: text("organization_id")
-// .notNull()
-// .references(() => organization.id, { onDelete: "cascade" }),
-// email: text("email").notNull(),
-// role: text("role"),
-// teamId: text("team_id"),
-// status: text("status").notNull(),
-// expiresAt: timestamp("expires_at").notNull(),
-// inviterId: text("inviter_id")
-// .notNull()
-// .references(() => user.id, { onDelete: "cascade" }),
-// });
diff --git a/packages/server/package.json b/packages/server/package.json
index 3265c95c..a57ff65e 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -35,11 +35,6 @@
"@ai-sdk/mistral": "^1.0.6",
"@ai-sdk/openai": "^1.0.12",
"@ai-sdk/openai-compatible": "^0.0.13",
- "@better-auth/utils":"0.2.3",
- "@oslojs/encoding":"1.1.0",
- "@oslojs/crypto":"1.0.1",
- "drizzle-dbml-generator":"0.10.0",
- "better-auth":"1.2.0",
"@faker-js/faker": "^8.4.1",
"@lucia-auth/adapter-drizzle": "1.0.7",
"@octokit/auth-app": "^6.0.4",
@@ -53,7 +48,7 @@
"date-fns": "3.6.0",
"dockerode": "4.0.2",
"dotenv": "16.4.5",
- "drizzle-orm": "^0.39.1",
+ "drizzle-orm": "^0.30.8",
"drizzle-zod": "0.5.1",
"hi-base32": "^0.5.1",
"js-yaml": "4.1.0",
@@ -93,7 +88,7 @@
"@types/react-dom": "^18.2.15",
"@types/ssh2": "1.15.1",
"@types/ws": "8.5.10",
- "drizzle-kit": "^0.30.4",
+ "drizzle-kit": "^0.21.1",
"esbuild": "0.20.2",
"esbuild-plugin-alias": "0.2.1",
"postcss": "^8.4.31",
diff --git a/packages/server/src/auth/auth.ts b/packages/server/src/auth/auth.ts
new file mode 100644
index 00000000..ab340d0a
--- /dev/null
+++ b/packages/server/src/auth/auth.ts
@@ -0,0 +1,117 @@
+import type { IncomingMessage, ServerResponse } from "node:http";
+import { findAdminByAuthId } from "@dokploy/server/services/admin";
+import { findUserByAuthId } from "@dokploy/server/services/user";
+import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle";
+import { TimeSpan } from "lucia";
+import { Lucia } from "lucia/dist/core.js";
+import type { Session, User } from "lucia/dist/core.js";
+import { db } from "../db";
+import { type DatabaseUser, auth, sessionTable } from "../db/schema";
+
+export const adapter = new DrizzlePostgreSQLAdapter(db, sessionTable, auth);
+
+export const lucia = new Lucia(adapter, {
+ sessionCookie: {
+ attributes: {
+ secure: false,
+ },
+ },
+ sessionExpiresIn: new TimeSpan(1, "d"),
+ getUserAttributes: (attributes) => {
+ return {
+ email: attributes.email,
+ rol: attributes.rol,
+ secret: attributes.secret !== null,
+ adminId: attributes.adminId,
+ };
+ },
+});
+
+declare module "lucia" {
+ interface Register {
+ Lucia: typeof lucia;
+ DatabaseUserAttributes: Omit & {
+ authId: string;
+ adminId: string;
+ };
+ }
+}
+
+export type ReturnValidateToken = Promise<{
+ user: (User & { authId: string; adminId: string }) | null;
+ session: Session | null;
+}>;
+
+export async function validateRequest(
+ req: IncomingMessage,
+ res: ServerResponse,
+): ReturnValidateToken {
+ const sessionId = lucia.readSessionCookie(req.headers.cookie ?? "");
+
+ if (!sessionId) {
+ return {
+ user: null,
+ session: null,
+ };
+ }
+ const result = await lucia.validateSession(sessionId);
+ if (result?.session?.fresh) {
+ res.appendHeader(
+ "Set-Cookie",
+ lucia.createSessionCookie(result.session.id).serialize(),
+ );
+ }
+ if (!result.session) {
+ res.appendHeader(
+ "Set-Cookie",
+ lucia.createBlankSessionCookie().serialize(),
+ );
+ }
+ if (result.user) {
+ try {
+ if (result.user?.rol === "admin") {
+ const admin = await findAdminByAuthId(result.user.id);
+ result.user.adminId = admin.adminId;
+ } else if (result.user?.rol === "user") {
+ const userResult = await findUserByAuthId(result.user.id);
+ result.user.adminId = userResult.adminId;
+ }
+ } catch (error) {
+ return {
+ user: null,
+ session: null,
+ };
+ }
+ }
+
+ return {
+ session: result.session,
+ ...((result.user && {
+ user: {
+ authId: result.user.id,
+ email: result.user.email,
+ rol: result.user.rol,
+ id: result.user.id,
+ secret: result.user.secret,
+ adminId: result.user.adminId,
+ },
+ }) || {
+ user: null,
+ }),
+ };
+}
+
+export async function validateWebSocketRequest(
+ req: IncomingMessage,
+): Promise<{ user: User; session: Session } | { user: null; session: null }> {
+ const sessionId = lucia.readSessionCookie(req.headers.cookie ?? "");
+
+ if (!sessionId) {
+ return {
+ user: null,
+ session: null,
+ };
+ }
+ const result = await lucia.validateSession(sessionId);
+ return result;
+}
diff --git a/packages/server/src/auth/token.ts b/packages/server/src/auth/token.ts
new file mode 100644
index 00000000..f29d4dbd
--- /dev/null
+++ b/packages/server/src/auth/token.ts
@@ -0,0 +1,99 @@
+import type { IncomingMessage } from "node:http";
+import { TimeSpan } from "lucia";
+import { Lucia } from "lucia/dist/core.js";
+import { findAdminByAuthId } from "../services/admin";
+import { findUserByAuthId } from "../services/user";
+import { type ReturnValidateToken, adapter } from "./auth";
+
+export const luciaToken = new Lucia(adapter, {
+ sessionCookie: {
+ attributes: {
+ secure: false,
+ },
+ },
+ sessionExpiresIn: new TimeSpan(365, "d"),
+ getUserAttributes: (attributes) => {
+ return {
+ email: attributes.email,
+ rol: attributes.rol,
+ secret: attributes.secret !== null,
+ };
+ },
+});
+
+export const validateBearerToken = async (
+ req: IncomingMessage,
+): ReturnValidateToken => {
+ const authorizationHeader = req.headers.authorization;
+ const sessionId = luciaToken.readBearerToken(authorizationHeader ?? "");
+ if (!sessionId) {
+ return {
+ user: null,
+ session: null,
+ };
+ }
+ const result = await luciaToken.validateSession(sessionId);
+
+ if (result.user) {
+ if (result.user?.rol === "admin") {
+ const admin = await findAdminByAuthId(result.user.id);
+ result.user.adminId = admin.adminId;
+ } else if (result.user?.rol === "user") {
+ const userResult = await findUserByAuthId(result.user.id);
+ result.user.adminId = userResult.adminId;
+ }
+ }
+ return {
+ session: result.session,
+ ...((result.user && {
+ user: {
+ adminId: result.user.adminId,
+ authId: result.user.id,
+ email: result.user.email,
+ rol: result.user.rol,
+ id: result.user.id,
+ secret: result.user.secret,
+ },
+ }) || {
+ user: null,
+ }),
+ };
+};
+
+export const validateBearerTokenAPI = async (
+ authorizationHeader: string,
+): ReturnValidateToken => {
+ const sessionId = luciaToken.readBearerToken(authorizationHeader ?? "");
+ if (!sessionId) {
+ return {
+ user: null,
+ session: null,
+ };
+ }
+ const result = await luciaToken.validateSession(sessionId);
+
+ if (result.user) {
+ if (result.user?.rol === "admin") {
+ const admin = await findAdminByAuthId(result.user.id);
+ result.user.adminId = admin.adminId;
+ } else if (result.user?.rol === "user") {
+ const userResult = await findUserByAuthId(result.user.id);
+ result.user.adminId = userResult.adminId;
+ }
+ }
+ return {
+ session: result.session,
+ ...((result.user && {
+ user: {
+ adminId: result.user.adminId,
+ authId: result.user.id,
+ email: result.user.email,
+ rol: result.user.rol,
+ id: result.user.id,
+ secret: result.user.secret,
+ },
+ }) || {
+ user: null,
+ }),
+ };
+};
diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts
deleted file mode 100644
index 8291ea4d..00000000
--- a/packages/server/src/db/schema/account.ts
+++ /dev/null
@@ -1,194 +0,0 @@
-import { relations, sql } from "drizzle-orm";
-import {
- boolean,
- integer,
- pgTable,
- text,
- timestamp,
-} from "drizzle-orm/pg-core";
-import { nanoid } from "nanoid";
-import { projects } from "./project";
-import { server } from "./server";
-import { users_temp } from "./user";
-
-export const account = pgTable("account", {
- id: text("id")
- .primaryKey()
- .$defaultFn(() => nanoid()),
- accountId: text("account_id")
- .notNull()
- .$defaultFn(() => nanoid()),
- providerId: text("provider_id").notNull(),
- userId: text("user_id")
- .notNull()
- .references(() => users_temp.id, { onDelete: "cascade" }),
- accessToken: text("access_token"),
- refreshToken: text("refresh_token"),
- idToken: text("id_token"),
- accessTokenExpiresAt: timestamp("access_token_expires_at"),
- refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
- scope: text("scope"),
- password: text("password"),
- is2FAEnabled: boolean("is2FAEnabled").notNull().default(false),
- createdAt: timestamp("created_at").notNull(),
- updatedAt: timestamp("updated_at").notNull(),
- resetPasswordToken: text("resetPasswordToken"),
- resetPasswordExpiresAt: text("resetPasswordExpiresAt"),
- confirmationToken: text("confirmationToken"),
- confirmationExpiresAt: text("confirmationExpiresAt"),
-});
-
-export const accountRelations = relations(account, ({ one }) => ({
- user: one(users_temp, {
- fields: [account.userId],
- references: [users_temp.id],
- }),
-}));
-
-export const verification = pgTable("verification", {
- id: text("id").primaryKey(),
- identifier: text("identifier").notNull(),
- value: text("value").notNull(),
- expiresAt: timestamp("expires_at").notNull(),
- createdAt: timestamp("created_at"),
- updatedAt: timestamp("updated_at"),
-});
-
-export const organization = pgTable("organization", {
- id: text("id")
- .primaryKey()
- .$defaultFn(() => nanoid()),
- name: text("name").notNull(),
- slug: text("slug").unique(),
- logo: text("logo"),
- createdAt: timestamp("created_at").notNull(),
- metadata: text("metadata"),
- ownerId: text("owner_id")
- .notNull()
- .references(() => users_temp.id, { onDelete: "cascade" }),
-});
-
-export const organizationRelations = relations(
- organization,
- ({ one, many }) => ({
- owner: one(users_temp, {
- fields: [organization.ownerId],
- references: [users_temp.id],
- }),
- servers: many(server),
- projects: many(projects),
- members: many(member),
- }),
-);
-
-export const member = pgTable("member", {
- id: text("id")
- .primaryKey()
- .$defaultFn(() => nanoid()),
- organizationId: text("organization_id")
- .notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
- userId: text("user_id")
- .notNull()
- .references(() => users_temp.id, { onDelete: "cascade" }),
- role: text("role").notNull().$type<"owner" | "member" | "admin">(),
- createdAt: timestamp("created_at").notNull(),
- teamId: text("team_id"),
- // Permissions
- canCreateProjects: boolean("canCreateProjects").notNull().default(false),
- canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false),
- canCreateServices: boolean("canCreateServices").notNull().default(false),
- canDeleteProjects: boolean("canDeleteProjects").notNull().default(false),
- canDeleteServices: boolean("canDeleteServices").notNull().default(false),
- canAccessToDocker: boolean("canAccessToDocker").notNull().default(false),
- canAccessToAPI: boolean("canAccessToAPI").notNull().default(false),
- canAccessToGitProviders: boolean("canAccessToGitProviders")
- .notNull()
- .default(false),
- canAccessToTraefikFiles: boolean("canAccessToTraefikFiles")
- .notNull()
- .default(false),
- accessedProjects: text("accesedProjects")
- .array()
- .notNull()
- .default(sql`ARRAY[]::text[]`),
- accessedServices: text("accesedServices")
- .array()
- .notNull()
- .default(sql`ARRAY[]::text[]`),
-});
-
-export const memberRelations = relations(member, ({ one }) => ({
- organization: one(organization, {
- fields: [member.organizationId],
- references: [organization.id],
- }),
- user: one(users_temp, {
- fields: [member.userId],
- references: [users_temp.id],
- }),
-}));
-
-export const invitation = pgTable("invitation", {
- id: text("id").primaryKey(),
- organizationId: text("organization_id")
- .notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
- email: text("email").notNull(),
- role: text("role").$type<"owner" | "member" | "admin">(),
- status: text("status").notNull(),
- expiresAt: timestamp("expires_at").notNull(),
- inviterId: text("inviter_id")
- .notNull()
- .references(() => users_temp.id, { onDelete: "cascade" }),
- teamId: text("team_id"),
-});
-
-export const invitationRelations = relations(invitation, ({ one }) => ({
- organization: one(organization, {
- fields: [invitation.organizationId],
- references: [organization.id],
- }),
-}));
-
-export const twoFactor = pgTable("two_factor", {
- id: text("id").primaryKey(),
- secret: text("secret").notNull(),
- backupCodes: text("backup_codes").notNull(),
- userId: text("user_id")
- .notNull()
- .references(() => users_temp.id, { onDelete: "cascade" }),
-});
-
-export const apikey = pgTable("apikey", {
- id: text("id").primaryKey(),
- name: text("name"),
- start: text("start"),
- prefix: text("prefix"),
- key: text("key").notNull(),
- userId: text("user_id")
- .notNull()
- .references(() => users_temp.id, { onDelete: "cascade" }),
- refillInterval: integer("refill_interval"),
- refillAmount: integer("refill_amount"),
- lastRefillAt: timestamp("last_refill_at"),
- enabled: boolean("enabled"),
- rateLimitEnabled: boolean("rate_limit_enabled"),
- rateLimitTimeWindow: integer("rate_limit_time_window"),
- rateLimitMax: integer("rate_limit_max"),
- requestCount: integer("request_count"),
- remaining: integer("remaining"),
- lastRequest: timestamp("last_request"),
- expiresAt: timestamp("expires_at"),
- createdAt: timestamp("created_at").notNull(),
- updatedAt: timestamp("updated_at").notNull(),
- permissions: text("permissions"),
- metadata: text("metadata"),
-});
-
-export const apikeyRelations = relations(apikey, ({ one }) => ({
- user: one(users_temp, {
- fields: [apikey.userId],
- references: [users_temp.id],
- }),
-}));
diff --git a/packages/server/src/db/schema/admin.ts b/packages/server/src/db/schema/admin.ts
new file mode 100644
index 00000000..f5b46fdd
--- /dev/null
+++ b/packages/server/src/db/schema/admin.ts
@@ -0,0 +1,121 @@
+import { relations } from "drizzle-orm";
+import { boolean, integer, pgTable, text } from "drizzle-orm/pg-core";
+import { createInsertSchema } from "drizzle-zod";
+import { nanoid } from "nanoid";
+import { z } from "zod";
+import { ai } from "./ai";
+import { auth } from "./auth";
+import { certificates } from "./certificate";
+import { registry } from "./registry";
+import { certificateType } from "./shared";
+import { sshKeys } from "./ssh-key";
+import { users } from "./user";
+
+export const admins = pgTable("admin", {
+ adminId: text("adminId")
+ .notNull()
+ .primaryKey()
+ .$defaultFn(() => nanoid()),
+ serverIp: text("serverIp"),
+ certificateType: certificateType("certificateType").notNull().default("none"),
+ host: text("host"),
+ letsEncryptEmail: text("letsEncryptEmail"),
+ sshPrivateKey: text("sshPrivateKey"),
+ enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
+ enableLogRotation: boolean("enableLogRotation").notNull().default(false),
+ authId: text("authId")
+ .notNull()
+ .references(() => auth.id, { onDelete: "cascade" }),
+ createdAt: text("createdAt")
+ .notNull()
+ .$defaultFn(() => new Date().toISOString()),
+ stripeCustomerId: text("stripeCustomerId"),
+ stripeSubscriptionId: text("stripeSubscriptionId"),
+ serversQuantity: integer("serversQuantity").notNull().default(0),
+});
+
+export const adminsRelations = relations(admins, ({ one, many }) => ({
+ auth: one(auth, {
+ fields: [admins.authId],
+ references: [auth.id],
+ }),
+ users: many(users),
+ registry: many(registry),
+ sshKeys: many(sshKeys),
+ certificates: many(certificates),
+ ai: many(ai),
+}));
+
+const createSchema = createInsertSchema(admins, {
+ adminId: z.string(),
+ enableDockerCleanup: z.boolean().optional(),
+ sshPrivateKey: z.string().optional(),
+ certificateType: z.enum(["letsencrypt", "none"]).default("none"),
+ serverIp: z.string().optional(),
+ letsEncryptEmail: z.string().optional(),
+});
+
+export const apiUpdateAdmin = createSchema.partial();
+
+export const apiSaveSSHKey = createSchema
+ .pick({
+ sshPrivateKey: true,
+ })
+ .required();
+
+export const apiAssignDomain = createSchema
+ .pick({
+ host: true,
+ certificateType: true,
+ letsEncryptEmail: true,
+ })
+ .required()
+ .partial({
+ letsEncryptEmail: true,
+ });
+
+export const apiUpdateDockerCleanup = createSchema
+ .pick({
+ enableDockerCleanup: true,
+ })
+ .required()
+ .extend({
+ serverId: z.string().optional(),
+ });
+
+export const apiTraefikConfig = z.object({
+ traefikConfig: z.string().min(1),
+});
+
+export const apiModifyTraefikConfig = z.object({
+ path: z.string().min(1),
+ traefikConfig: z.string().min(1),
+ serverId: z.string().optional(),
+});
+export const apiReadTraefikConfig = z.object({
+ path: z.string().min(1),
+ serverId: z.string().optional(),
+});
+
+export const apiEnableDashboard = z.object({
+ enableDashboard: z.boolean().optional(),
+ serverId: z.string().optional(),
+});
+
+export const apiServerSchema = z
+ .object({
+ serverId: z.string().optional(),
+ })
+ .optional();
+
+export const apiReadStatsLogs = z.object({
+ page: z
+ .object({
+ pageIndex: z.number(),
+ pageSize: z.number(),
+ })
+ .optional(),
+ status: z.string().array().optional(),
+ search: z.string().optional(),
+ sort: z.object({ id: z.string(), desc: z.boolean() }).optional(),
+});
diff --git a/packages/server/src/db/schema/application.ts b/packages/server/src/db/schema/application.ts
index e670e2e2..2437f59d 100644
--- a/packages/server/src/db/schema/application.ts
+++ b/packages/server/src/db/schema/application.ts
@@ -44,6 +44,7 @@ export const buildType = pgEnum("buildType", [
"static",
]);
+// TODO: refactor this types
export interface HealthCheckSwarm {
Test?: string[] | undefined;
Interval?: number | undefined;
diff --git a/packages/server/src/db/schema/auth.ts b/packages/server/src/db/schema/auth.ts
new file mode 100644
index 00000000..3e16c68e
--- /dev/null
+++ b/packages/server/src/db/schema/auth.ts
@@ -0,0 +1,130 @@
+import { getRandomValues } from "node:crypto";
+import { relations } from "drizzle-orm";
+import { boolean, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
+import { createInsertSchema } from "drizzle-zod";
+import { nanoid } from "nanoid";
+import { z } from "zod";
+import { admins } from "./admin";
+import { users } from "./user";
+
+const randomImages = [
+ "/avatars/avatar-1.png",
+ "/avatars/avatar-2.png",
+ "/avatars/avatar-3.png",
+ "/avatars/avatar-4.png",
+ "/avatars/avatar-5.png",
+ "/avatars/avatar-6.png",
+ "/avatars/avatar-7.png",
+ "/avatars/avatar-8.png",
+ "/avatars/avatar-9.png",
+ "/avatars/avatar-10.png",
+ "/avatars/avatar-11.png",
+ "/avatars/avatar-12.png",
+];
+
+const generateRandomImage = () => {
+ return (
+ randomImages[
+ // @ts-ignore
+ getRandomValues(new Uint32Array(1))[0] % randomImages.length
+ ] || "/avatars/avatar-1.png"
+ );
+};
+export type DatabaseUser = typeof auth.$inferSelect;
+export const roles = pgEnum("Roles", ["admin", "user"]);
+
+export const auth = pgTable("auth", {
+ id: text("id")
+ .notNull()
+ .primaryKey()
+ .$defaultFn(() => nanoid()),
+ email: text("email").notNull().unique(),
+ password: text("password").notNull(),
+ rol: roles("rol").notNull(),
+ image: text("image").$defaultFn(() => generateRandomImage()),
+ secret: text("secret"),
+ token: text("token"),
+ is2FAEnabled: boolean("is2FAEnabled").notNull().default(false),
+ createdAt: text("createdAt")
+ .notNull()
+ .$defaultFn(() => new Date().toISOString()),
+ resetPasswordToken: text("resetPasswordToken"),
+ resetPasswordExpiresAt: text("resetPasswordExpiresAt"),
+ confirmationToken: text("confirmationToken"),
+ confirmationExpiresAt: text("confirmationExpiresAt"),
+});
+
+export const authRelations = relations(auth, ({ many }) => ({
+ admins: many(admins),
+ users: many(users),
+}));
+const createSchema = createInsertSchema(auth, {
+ email: z.string().email(),
+ password: z.string().min(8),
+ rol: z.enum(["admin", "user"]),
+ image: z.string().optional(),
+});
+
+export const apiCreateAdmin = createSchema.pick({
+ email: true,
+ password: true,
+});
+
+export const apiCreateUser = createSchema
+ .pick({
+ password: true,
+ id: true,
+ token: true,
+ })
+ .required()
+ .extend({
+ token: z.string().min(1),
+ });
+
+export const apiLogin = createSchema
+ .pick({
+ email: true,
+ password: true,
+ })
+ .required();
+
+export const apiUpdateAuth = createSchema.partial().extend({
+ email: z.string().nullable(),
+ password: z.string().nullable(),
+ image: z.string().optional(),
+ currentPassword: z.string().nullable(),
+});
+
+export const apiUpdateAuthByAdmin = createSchema.partial().extend({
+ email: z.string().nullable(),
+ password: z.string().nullable(),
+ image: z.string().optional(),
+ id: z.string().min(1),
+});
+
+export const apiFindOneAuth = createSchema
+ .pick({
+ id: true,
+ })
+ .required();
+
+export const apiVerify2FA = createSchema
+ .extend({
+ pin: z.string().min(6),
+ secret: z.string().min(1),
+ })
+ .pick({
+ pin: true,
+ secret: true,
+ })
+ .required();
+
+export const apiVerifyLogin2FA = createSchema
+ .extend({
+ pin: z.string().min(6),
+ })
+ .pick({
+ pin: true,
+ id: true,
+ })
+ .required();
diff --git a/packages/server/src/db/schema/bitbucket.ts b/packages/server/src/db/schema/bitbucket.ts
index 0311202d..393cb1e7 100644
--- a/packages/server/src/db/schema/bitbucket.ts
+++ b/packages/server/src/db/schema/bitbucket.ts
@@ -61,5 +61,5 @@ export const apiUpdateBitbucket = createSchema.extend({
name: z.string().min(1),
bitbucketUsername: z.string().optional(),
bitbucketWorkspaceName: z.string().optional(),
- organizationId: z.string().optional(),
+ adminId: z.string().optional(),
});
diff --git a/packages/server/src/db/schema/certificate.ts b/packages/server/src/db/schema/certificate.ts
index bf72f7db..1df61be8 100644
--- a/packages/server/src/db/schema/certificate.ts
+++ b/packages/server/src/db/schema/certificate.ts
@@ -3,7 +3,7 @@ import { boolean, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
-import { organization } from "./account";
+import { admins } from "./admin";
import { server } from "./server";
import { generateAppName } from "./utils";
@@ -20,24 +20,27 @@ export const certificates = pgTable("certificate", {
.$defaultFn(() => generateAppName("certificate"))
.unique(),
autoRenew: boolean("autoRenew"),
- organizationId: text("organizationId")
- .notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
+ adminId: text("adminId").references(() => admins.adminId, {
+ onDelete: "cascade",
+ }),
serverId: text("serverId").references(() => server.serverId, {
onDelete: "cascade",
}),
});
-export const certificatesRelations = relations(certificates, ({ one }) => ({
- server: one(server, {
- fields: [certificates.serverId],
- references: [server.serverId],
+export const certificatesRelations = relations(
+ certificates,
+ ({ one, many }) => ({
+ server: one(server, {
+ fields: [certificates.serverId],
+ references: [server.serverId],
+ }),
+ admin: one(admins, {
+ fields: [certificates.adminId],
+ references: [admins.adminId],
+ }),
}),
- organization: one(organization, {
- fields: [certificates.organizationId],
- references: [organization.id],
- }),
-}));
+);
export const apiCreateCertificate = createInsertSchema(certificates, {
name: z.string().min(1),
diff --git a/packages/server/src/db/schema/compose.ts b/packages/server/src/db/schema/compose.ts
index ca8344ee..e0c4863b 100644
--- a/packages/server/src/db/schema/compose.ts
+++ b/packages/server/src/db/schema/compose.ts
@@ -69,7 +69,6 @@ export const compose = pgTable("compose", {
composePath: text("composePath").notNull().default("./docker-compose.yml"),
suffix: text("suffix").notNull().default(""),
randomize: boolean("randomize").notNull().default(false),
- isolatedDeployment: boolean("isolatedDeployment").notNull().default(false),
composeStatus: applicationStatus("composeStatus").notNull().default("idle"),
projectId: text("projectId")
.notNull()
diff --git a/packages/server/src/db/schema/dbml.ts b/packages/server/src/db/schema/dbml.ts
deleted file mode 100644
index 72a75814..00000000
--- a/packages/server/src/db/schema/dbml.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { pgGenerate } from "drizzle-dbml-generator"; // Using Postgres for this example
-import * as schema from "./index";
-
-const out = "./schema.dbml";
-const relational = true;
-
-pgGenerate({ schema, out, relational });
diff --git a/packages/server/src/db/schema/deployment.ts b/packages/server/src/db/schema/deployment.ts
index 4dfed76b..ccaf6466 100644
--- a/packages/server/src/db/schema/deployment.ts
+++ b/packages/server/src/db/schema/deployment.ts
@@ -1,4 +1,4 @@
-import { relations } from "drizzle-orm";
+import { is, relations } from "drizzle-orm";
import {
type AnyPgColumn,
boolean,
@@ -47,7 +47,6 @@ export const deployments = pgTable("deployment", {
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
- errorMessage: text("errorMessage"),
});
export const deploymentsRelations = relations(deployments, ({ one }) => ({
diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts
index 0aeb1490..7d7be614 100644
--- a/packages/server/src/db/schema/destination.ts
+++ b/packages/server/src/db/schema/destination.ts
@@ -3,7 +3,7 @@ import { pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
-import { organization } from "./account";
+import { admins } from "./admin";
import { backups } from "./backups";
export const destinations = pgTable("destination", {
@@ -17,19 +17,20 @@ export const destinations = pgTable("destination", {
secretAccessKey: text("secretAccessKey").notNull(),
bucket: text("bucket").notNull(),
region: text("region").notNull(),
+ // maybe it can be null
endpoint: text("endpoint").notNull(),
- organizationId: text("organizationId")
+ adminId: text("adminId")
.notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
+ .references(() => admins.adminId, { onDelete: "cascade" }),
});
export const destinationsRelations = relations(
destinations,
({ many, one }) => ({
backups: many(backups),
- organization: one(organization, {
- fields: [destinations.organizationId],
- references: [organization.id],
+ admin: one(admins, {
+ fields: [destinations.adminId],
+ references: [admins.adminId],
}),
}),
);
diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts
index 92230737..dbbfc183 100644
--- a/packages/server/src/db/schema/git-provider.ts
+++ b/packages/server/src/db/schema/git-provider.ts
@@ -3,7 +3,7 @@ import { pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
-import { organization } from "./account";
+import { admins } from "./admin";
import { bitbucket } from "./bitbucket";
import { github } from "./github";
import { gitlab } from "./gitlab";
@@ -24,12 +24,12 @@ export const gitProvider = pgTable("git_provider", {
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
- organizationId: text("organizationId")
- .notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
+ adminId: text("adminId").references(() => admins.adminId, {
+ onDelete: "cascade",
+ }),
});
-export const gitProviderRelations = relations(gitProvider, ({ one }) => ({
+export const gitProviderRelations = relations(gitProvider, ({ one, many }) => ({
github: one(github, {
fields: [gitProvider.gitProviderId],
references: [github.gitProviderId],
@@ -42,9 +42,9 @@ export const gitProviderRelations = relations(gitProvider, ({ one }) => ({
fields: [gitProvider.gitProviderId],
references: [bitbucket.gitProviderId],
}),
- organization: one(organization, {
- fields: [gitProvider.organizationId],
- references: [organization.id],
+ admin: one(admins, {
+ fields: [gitProvider.adminId],
+ references: [admins.adminId],
}),
}));
diff --git a/packages/server/src/db/schema/index.ts b/packages/server/src/db/schema/index.ts
index 0b453fac..6d335632 100644
--- a/packages/server/src/db/schema/index.ts
+++ b/packages/server/src/db/schema/index.ts
@@ -1,6 +1,8 @@
export * from "./application";
export * from "./postgres";
export * from "./user";
+export * from "./admin";
+export * from "./auth";
export * from "./project";
export * from "./domain";
export * from "./mariadb";
@@ -29,4 +31,3 @@ export * from "./server";
export * from "./utils";
export * from "./preview-deployments";
export * from "./ai";
-export * from "./account";
diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts
index 1c8a2d8f..12c7698e 100644
--- a/packages/server/src/db/schema/notification.ts
+++ b/packages/server/src/db/schema/notification.ts
@@ -3,7 +3,7 @@ import { boolean, integer, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
-import { organization } from "./account";
+import { admins } from "./admin";
export const notificationType = pgEnum("notificationType", [
"slack",
@@ -24,7 +24,6 @@ export const notifications = pgTable("notification", {
databaseBackup: boolean("databaseBackup").notNull().default(false),
dokployRestart: boolean("dokployRestart").notNull().default(false),
dockerCleanup: boolean("dockerCleanup").notNull().default(false),
- serverThreshold: boolean("serverThreshold").notNull().default(false),
notificationType: notificationType("notificationType").notNull(),
createdAt: text("createdAt")
.notNull()
@@ -44,9 +43,9 @@ export const notifications = pgTable("notification", {
gotifyId: text("gotifyId").references(() => gotify.gotifyId, {
onDelete: "cascade",
}),
- organizationId: text("organizationId")
- .notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
+ adminId: text("adminId").references(() => admins.adminId, {
+ onDelete: "cascade",
+ }),
});
export const slack = pgTable("slack", {
@@ -65,7 +64,6 @@ export const telegram = pgTable("telegram", {
.$defaultFn(() => nanoid()),
botToken: text("botToken").notNull(),
chatId: text("chatId").notNull(),
- messageThreadId: text("messageThreadId"),
});
export const discord = pgTable("discord", {
@@ -122,9 +120,9 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({
fields: [notifications.gotifyId],
references: [gotify.gotifyId],
}),
- organization: one(organization, {
- fields: [notifications.organizationId],
- references: [organization.id],
+ admin: one(admins, {
+ fields: [notifications.adminId],
+ references: [admins.adminId],
}),
}));
@@ -138,7 +136,6 @@ export const apiCreateSlack = notificationsSchema
name: true,
appDeploy: true,
dockerCleanup: true,
- serverThreshold: true,
})
.extend({
webhookUrl: z.string().min(1),
@@ -149,7 +146,7 @@ export const apiCreateSlack = notificationsSchema
export const apiUpdateSlack = apiCreateSlack.partial().extend({
notificationId: z.string().min(1),
slackId: z.string(),
- organizationId: z.string().optional(),
+ adminId: z.string().optional(),
});
export const apiTestSlackConnection = apiCreateSlack.pick({
@@ -165,25 +162,22 @@ export const apiCreateTelegram = notificationsSchema
name: true,
appDeploy: true,
dockerCleanup: true,
- serverThreshold: true,
})
.extend({
botToken: z.string().min(1),
chatId: z.string().min(1),
- messageThreadId: z.string(),
})
.required();
export const apiUpdateTelegram = apiCreateTelegram.partial().extend({
notificationId: z.string().min(1),
telegramId: z.string().min(1),
- organizationId: z.string().optional(),
+ adminId: z.string().optional(),
});
export const apiTestTelegramConnection = apiCreateTelegram.pick({
botToken: true,
chatId: true,
- messageThreadId: true,
});
export const apiCreateDiscord = notificationsSchema
@@ -194,7 +188,6 @@ export const apiCreateDiscord = notificationsSchema
name: true,
appDeploy: true,
dockerCleanup: true,
- serverThreshold: true,
})
.extend({
webhookUrl: z.string().min(1),
@@ -205,7 +198,7 @@ export const apiCreateDiscord = notificationsSchema
export const apiUpdateDiscord = apiCreateDiscord.partial().extend({
notificationId: z.string().min(1),
discordId: z.string().min(1),
- organizationId: z.string().optional(),
+ adminId: z.string().optional(),
});
export const apiTestDiscordConnection = apiCreateDiscord
@@ -224,7 +217,6 @@ export const apiCreateEmail = notificationsSchema
name: true,
appDeploy: true,
dockerCleanup: true,
- serverThreshold: true,
})
.extend({
smtpServer: z.string().min(1),
@@ -239,7 +231,7 @@ export const apiCreateEmail = notificationsSchema
export const apiUpdateEmail = apiCreateEmail.partial().extend({
notificationId: z.string().min(1),
emailId: z.string().min(1),
- organizationId: z.string().optional(),
+ adminId: z.string().optional(),
});
export const apiTestEmailConnection = apiCreateEmail.pick({
@@ -271,7 +263,7 @@ export const apiCreateGotify = notificationsSchema
export const apiUpdateGotify = apiCreateGotify.partial().extend({
notificationId: z.string().min(1),
gotifyId: z.string().min(1),
- organizationId: z.string().optional(),
+ adminId: z.string().optional(),
});
export const apiTestGotifyConnection = apiCreateGotify
diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts
index deeba4ac..7ed140d6 100644
--- a/packages/server/src/db/schema/project.ts
+++ b/packages/server/src/db/schema/project.ts
@@ -1,9 +1,10 @@
import { relations } from "drizzle-orm";
+
import { pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
-import { organization } from "./account";
+import { admins } from "./admin";
import { applications } from "./application";
import { compose } from "./compose";
import { mariadb } from "./mariadb";
@@ -22,10 +23,9 @@ export const projects = pgTable("project", {
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
-
- organizationId: text("organizationId")
+ adminId: text("adminId")
.notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
+ .references(() => admins.adminId, { onDelete: "cascade" }),
env: text("env").notNull().default(""),
});
@@ -37,9 +37,9 @@ export const projectRelations = relations(projects, ({ many, one }) => ({
mongo: many(mongo),
redis: many(redis),
compose: many(compose),
- organization: one(organization, {
- fields: [projects.organizationId],
- references: [organization.id],
+ admin: one(admins, {
+ fields: [projects.adminId],
+ references: [admins.adminId],
}),
}));
diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts
index b1874709..20544a58 100644
--- a/packages/server/src/db/schema/registry.ts
+++ b/packages/server/src/db/schema/registry.ts
@@ -3,7 +3,7 @@ import { pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
-import { organization } from "./account";
+import { admins } from "./admin";
import { applications } from "./application";
/**
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
@@ -27,12 +27,16 @@ export const registry = pgTable("registry", {
.notNull()
.$defaultFn(() => new Date().toISOString()),
registryType: registryType("selfHosted").notNull().default("cloud"),
- organizationId: text("organizationId")
+ adminId: text("adminId")
.notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
+ .references(() => admins.adminId, { onDelete: "cascade" }),
});
-export const registryRelations = relations(registry, ({ many }) => ({
+export const registryRelations = relations(registry, ({ one, many }) => ({
+ admin: one(admins, {
+ fields: [registry.adminId],
+ references: [admins.adminId],
+ }),
applications: many(applications),
}));
@@ -41,7 +45,7 @@ const createSchema = createInsertSchema(registry, {
username: z.string().min(1),
password: z.string().min(1),
registryUrl: z.string(),
- organizationId: z.string().min(1),
+ adminId: z.string().min(1),
registryId: z.string().min(1),
registryType: z.enum(["cloud"]),
imagePrefix: z.string().nullable().optional(),
diff --git a/packages/server/src/db/schema/schema.dbml b/packages/server/src/db/schema/schema.dbml
deleted file mode 100644
index ce2b5abc..00000000
--- a/packages/server/src/db/schema/schema.dbml
+++ /dev/null
@@ -1,872 +0,0 @@
-enum applicationStatus {
- idle
- running
- done
- error
-}
-
-enum buildType {
- dockerfile
- heroku_buildpacks
- paketo_buildpacks
- nixpacks
- static
-}
-
-enum certificateType {
- letsencrypt
- none
-}
-
-enum composeType {
- "docker-compose"
- stack
-}
-
-enum databaseType {
- postgres
- mariadb
- mysql
- mongo
-}
-
-enum deploymentStatus {
- running
- done
- error
-}
-
-enum domainType {
- compose
- application
- preview
-}
-
-enum gitProviderType {
- github
- gitlab
- bitbucket
-}
-
-enum mountType {
- bind
- volume
- file
-}
-
-enum notificationType {
- slack
- telegram
- discord
- email
- gotify
-}
-
-enum protocolType {
- tcp
- udp
-}
-
-enum RegistryType {
- selfHosted
- cloud
-}
-
-enum Roles {
- admin
- user
-}
-
-enum serverStatus {
- active
- inactive
-}
-
-enum serviceType {
- application
- postgres
- mysql
- mariadb
- mongo
- redis
- compose
-}
-
-enum sourceType {
- docker
- git
- github
- gitlab
- bitbucket
- drop
-}
-
-enum sourceTypeCompose {
- git
- github
- gitlab
- bitbucket
- raw
-}
-
-table account {
- id text [pk, not null]
- account_id text [not null]
- provider_id text [not null]
- user_id text [not null]
- access_token text
- refresh_token text
- id_token text
- access_token_expires_at timestamp
- refresh_token_expires_at timestamp
- scope text
- password text
- is2FAEnabled boolean [not null, default: false]
- created_at timestamp [not null]
- updated_at timestamp [not null]
- resetPasswordToken text
- resetPasswordExpiresAt text
- confirmationToken text
- confirmationExpiresAt text
-}
-
-table admin {
-}
-
-table application {
- applicationId text [pk, not null]
- name text [not null]
- appName text [not null, unique]
- description text
- env text
- previewEnv text
- previewBuildArgs text
- previewWildcard text
- previewPort integer [default: 3000]
- previewHttps boolean [not null, default: false]
- previewPath text [default: '/']
- certificateType certificateType [not null, default: 'none']
- previewLimit integer [default: 3]
- isPreviewDeploymentsActive boolean [default: false]
- buildArgs text
- memoryReservation text
- memoryLimit text
- cpuReservation text
- cpuLimit text
- title text
- enabled boolean
- subtitle text
- command text
- refreshToken text
- sourceType sourceType [not null, default: 'github']
- repository text
- owner text
- branch text
- buildPath text [default: '/']
- autoDeploy boolean
- gitlabProjectId integer
- gitlabRepository text
- gitlabOwner text
- gitlabBranch text
- gitlabBuildPath text [default: '/']
- gitlabPathNamespace text
- bitbucketRepository text
- bitbucketOwner text
- bitbucketBranch text
- bitbucketBuildPath text [default: '/']
- username text
- password text
- dockerImage text
- registryUrl text
- customGitUrl text
- customGitBranch text
- customGitBuildPath text
- customGitSSHKeyId text
- dockerfile text
- dockerContextPath text
- dockerBuildStage text
- dropBuildPath text
- healthCheckSwarm json
- restartPolicySwarm json
- placementSwarm json
- updateConfigSwarm json
- rollbackConfigSwarm json
- modeSwarm json
- labelsSwarm json
- networkSwarm json
- replicas integer [not null, default: 1]
- applicationStatus applicationStatus [not null, default: 'idle']
- buildType buildType [not null, default: 'nixpacks']
- herokuVersion text [default: '24']
- publishDirectory text
- createdAt text [not null]
- registryId text
- projectId text [not null]
- githubId text
- gitlabId text
- bitbucketId text
- serverId text
-}
-
-table auth {
- id text [pk, not null]
- email text [not null, unique]
- password text [not null]
- rol Roles [not null]
- image text
- secret text
- token text
- is2FAEnabled boolean [not null, default: false]
- createdAt text [not null]
- resetPasswordToken text
- resetPasswordExpiresAt text
- confirmationToken text
- confirmationExpiresAt text
-}
-
-table backup {
- backupId text [pk, not null]
- schedule text [not null]
- enabled boolean
- database text [not null]
- prefix text [not null]
- destinationId text [not null]
- databaseType databaseType [not null]
- postgresId text
- mariadbId text
- mysqlId text
- mongoId text
-}
-
-table bitbucket {
- bitbucketId text [pk, not null]
- bitbucketUsername text
- appPassword text
- bitbucketWorkspaceName text
- gitProviderId text [not null]
-}
-
-table certificate {
- certificateId text [pk, not null]
- name text [not null]
- certificateData text [not null]
- privateKey text [not null]
- certificatePath text [not null, unique]
- autoRenew boolean
- userId text
- serverId text
-}
-
-table compose {
- composeId text [pk, not null]
- name text [not null]
- appName text [not null]
- description text
- env text
- composeFile text [not null, default: '']
- refreshToken text
- sourceType sourceTypeCompose [not null, default: 'github']
- composeType composeType [not null, default: 'docker-compose']
- repository text
- owner text
- branch text
- autoDeploy boolean
- gitlabProjectId integer
- gitlabRepository text
- gitlabOwner text
- gitlabBranch text
- gitlabPathNamespace text
- bitbucketRepository text
- bitbucketOwner text
- bitbucketBranch text
- customGitUrl text
- customGitBranch text
- customGitSSHKeyId text
- command text [not null, default: '']
- composePath text [not null, default: './docker-compose.yml']
- suffix text [not null, default: '']
- randomize boolean [not null, default: false]
- isolatedDeployment boolean [not null, default: false]
- composeStatus applicationStatus [not null, default: 'idle']
- projectId text [not null]
- createdAt text [not null]
- githubId text
- gitlabId text
- bitbucketId text
- serverId text
-}
-
-table deployment {
- deploymentId text [pk, not null]
- title text [not null]
- description text
- status deploymentStatus [default: 'running']
- logPath text [not null]
- applicationId text
- composeId text
- serverId text
- isPreviewDeployment boolean [default: false]
- previewDeploymentId text
- createdAt text [not null]
- errorMessage text
-}
-
-table destination {
- destinationId text [pk, not null]
- name text [not null]
- provider text
- accessKey text [not null]
- secretAccessKey text [not null]
- bucket text [not null]
- region text [not null]
- endpoint text [not null]
- userId text [not null]
-}
-
-table discord {
- discordId text [pk, not null]
- webhookUrl text [not null]
- decoration boolean
-}
-
-table domain {
- domainId text [pk, not null]
- host text [not null]
- https boolean [not null, default: false]
- port integer [default: 3000]
- path text [default: '/']
- serviceName text
- domainType domainType [default: 'application']
- uniqueConfigKey serial [not null, increment]
- createdAt text [not null]
- composeId text
- applicationId text
- previewDeploymentId text
- certificateType certificateType [not null, default: 'none']
-}
-
-table email {
- emailId text [pk, not null]
- smtpServer text [not null]
- smtpPort integer [not null]
- username text [not null]
- password text [not null]
- fromAddress text [not null]
- toAddress text[] [not null]
-}
-
-table git_provider {
- gitProviderId text [pk, not null]
- name text [not null]
- providerType gitProviderType [not null, default: 'github']
- createdAt text [not null]
- userId text
-}
-
-table github {
- githubId text [pk, not null]
- githubAppName text
- githubAppId integer
- githubClientId text
- githubClientSecret text
- githubInstallationId text
- githubPrivateKey text
- githubWebhookSecret text
- gitProviderId text [not null]
-}
-
-table gitlab {
- gitlabId text [pk, not null]
- gitlabUrl text [not null, default: 'https://gitlab.com']
- application_id text
- redirect_uri text
- secret text
- access_token text
- refresh_token text
- group_name text
- expires_at integer
- gitProviderId text [not null]
-}
-
-table gotify {
- gotifyId text [pk, not null]
- serverUrl text [not null]
- appToken text [not null]
- priority integer [not null, default: 5]
- decoration boolean
-}
-
-table invitation {
- id text [pk, not null]
- organization_id text [not null]
- email text [not null]
- role text
- status text [not null]
- expires_at timestamp [not null]
- inviter_id text [not null]
-}
-
-table mariadb {
- mariadbId text [pk, not null]
- name text [not null]
- appName text [not null, unique]
- description text
- databaseName text [not null]
- databaseUser text [not null]
- databasePassword text [not null]
- rootPassword text [not null]
- dockerImage text [not null]
- command text
- env text
- memoryReservation text
- memoryLimit text
- cpuReservation text
- cpuLimit text
- externalPort integer
- applicationStatus applicationStatus [not null, default: 'idle']
- createdAt text [not null]
- projectId text [not null]
- serverId text
-}
-
-table member {
- id text [pk, not null]
- organization_id text [not null]
- user_id text [not null]
- role text [not null]
- created_at timestamp [not null]
-}
-
-table mongo {
- mongoId text [pk, not null]
- name text [not null]
- appName text [not null, unique]
- description text
- databaseUser text [not null]
- databasePassword text [not null]
- dockerImage text [not null]
- command text
- env text
- memoryReservation text
- memoryLimit text
- cpuReservation text
- cpuLimit text
- externalPort integer
- applicationStatus applicationStatus [not null, default: 'idle']
- createdAt text [not null]
- projectId text [not null]
- serverId text
- replicaSets boolean [default: false]
-}
-
-table mount {
- mountId text [pk, not null]
- type mountType [not null]
- hostPath text
- volumeName text
- filePath text
- content text
- serviceType serviceType [not null, default: 'application']
- mountPath text [not null]
- applicationId text
- postgresId text
- mariadbId text
- mongoId text
- mysqlId text
- redisId text
- composeId text
-}
-
-table mysql {
- mysqlId text [pk, not null]
- name text [not null]
- appName text [not null, unique]
- description text
- databaseName text [not null]
- databaseUser text [not null]
- databasePassword text [not null]
- rootPassword text [not null]
- dockerImage text [not null]
- command text
- env text
- memoryReservation text
- memoryLimit text
- cpuReservation text
- cpuLimit text
- externalPort integer
- applicationStatus applicationStatus [not null, default: 'idle']
- createdAt text [not null]
- projectId text [not null]
- serverId text
-}
-
-table notification {
- notificationId text [pk, not null]
- name text [not null]
- appDeploy boolean [not null, default: false]
- appBuildError boolean [not null, default: false]
- databaseBackup boolean [not null, default: false]
- dokployRestart boolean [not null, default: false]
- dockerCleanup boolean [not null, default: false]
- serverThreshold boolean [not null, default: false]
- notificationType notificationType [not null]
- createdAt text [not null]
- slackId text
- telegramId text
- discordId text
- emailId text
- gotifyId text
- userId text
-}
-
-table organization {
- id text [pk, not null]
- name text [not null]
- slug text [unique]
- logo text
- created_at timestamp [not null]
- metadata text
- owner_id text [not null]
-}
-
-table port {
- portId text [pk, not null]
- publishedPort integer [not null]
- targetPort integer [not null]
- protocol protocolType [not null]
- applicationId text [not null]
-}
-
-table postgres {
- postgresId text [pk, not null]
- name text [not null]
- appName text [not null, unique]
- databaseName text [not null]
- databaseUser text [not null]
- databasePassword text [not null]
- description text
- dockerImage text [not null]
- command text
- env text
- memoryReservation text
- externalPort integer
- memoryLimit text
- cpuReservation text
- cpuLimit text
- applicationStatus applicationStatus [not null, default: 'idle']
- createdAt text [not null]
- projectId text [not null]
- serverId text
-}
-
-table preview_deployments {
- previewDeploymentId text [pk, not null]
- branch text [not null]
- pullRequestId text [not null]
- pullRequestNumber text [not null]
- pullRequestURL text [not null]
- pullRequestTitle text [not null]
- pullRequestCommentId text [not null]
- previewStatus applicationStatus [not null, default: 'idle']
- appName text [not null, unique]
- applicationId text [not null]
- domainId text
- createdAt text [not null]
- expiresAt text
-}
-
-table project {
- projectId text [pk, not null]
- name text [not null]
- description text
- createdAt text [not null]
- userId text [not null]
- env text [not null, default: '']
-}
-
-table redirect {
- redirectId text [pk, not null]
- regex text [not null]
- replacement text [not null]
- permanent boolean [not null, default: false]
- uniqueConfigKey serial [not null, increment]
- createdAt text [not null]
- applicationId text [not null]
-}
-
-table redis {
- redisId text [pk, not null]
- name text [not null]
- appName text [not null, unique]
- description text
- password text [not null]
- dockerImage text [not null]
- command text
- env text
- memoryReservation text
- memoryLimit text
- cpuReservation text
- cpuLimit text
- externalPort integer
- createdAt text [not null]
- applicationStatus applicationStatus [not null, default: 'idle']
- projectId text [not null]
- serverId text
-}
-
-table registry {
- registryId text [pk, not null]
- registryName text [not null]
- imagePrefix text
- username text [not null]
- password text [not null]
- registryUrl text [not null, default: '']
- createdAt text [not null]
- selfHosted RegistryType [not null, default: 'cloud']
- userId text [not null]
-}
-
-table security {
- securityId text [pk, not null]
- username text [not null]
- password text [not null]
- createdAt text [not null]
- applicationId text [not null]
-
- indexes {
- (username, applicationId) [name: 'security_username_applicationId_unique', unique]
- }
-}
-
-table server {
- serverId text [pk, not null]
- name text [not null]
- description text
- ipAddress text [not null]
- port integer [not null]
- username text [not null, default: 'root']
- appName text [not null]
- enableDockerCleanup boolean [not null, default: false]
- createdAt text [not null]
- userId text [not null]
- serverStatus serverStatus [not null, default: 'active']
- command text [not null, default: '']
- sshKeyId text
- metricsConfig jsonb [not null, default: `{"server":{"type":"Remote","refreshRate":60,"port":4500,"token":"","urlCallback":"","cronJob":"","retentionDays":2,"thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}`]
-}
-
-table session {
- id text [pk, not null]
- expires_at timestamp [not null]
- token text [not null, unique]
- created_at timestamp [not null]
- updated_at timestamp [not null]
- ip_address text
- user_agent text
- user_id text [not null]
- impersonated_by text
- active_organization_id text
-}
-
-table slack {
- slackId text [pk, not null]
- webhookUrl text [not null]
- channel text
-}
-
-table "ssh-key" {
- sshKeyId text [pk, not null]
- privateKey text [not null, default: '']
- publicKey text [not null]
- name text [not null]
- description text
- createdAt text [not null]
- lastUsedAt text
- userId text
-}
-
-table telegram {
- telegramId text [pk, not null]
- botToken text [not null]
- chatId text [not null]
-}
-
-table user {
- id text [pk, not null]
- name text [not null, default: '']
- token text [not null]
- isRegistered boolean [not null, default: false]
- expirationDate text [not null]
- createdAt text [not null]
- canCreateProjects boolean [not null, default: false]
- canAccessToSSHKeys boolean [not null, default: false]
- canCreateServices boolean [not null, default: false]
- canDeleteProjects boolean [not null, default: false]
- canDeleteServices boolean [not null, default: false]
- canAccessToDocker boolean [not null, default: false]
- canAccessToAPI boolean [not null, default: false]
- canAccessToGitProviders boolean [not null, default: false]
- canAccessToTraefikFiles boolean [not null, default: false]
- accesedProjects text[] [not null, default: `ARRAY[]::text[]`]
- accesedServices text[] [not null, default: `ARRAY[]::text[]`]
- email text [not null, unique]
- email_verified boolean [not null]
- image text
- role text
- banned boolean
- ban_reason text
- ban_expires timestamp
- updated_at timestamp [not null]
- serverIp text
- certificateType certificateType [not null, default: 'none']
- host text
- letsEncryptEmail text
- sshPrivateKey text
- enableDockerCleanup boolean [not null, default: false]
- enableLogRotation boolean [not null, default: false]
- enablePaidFeatures boolean [not null, default: false]
- metricsConfig jsonb [not null, default: `{"server":{"type":"Dokploy","refreshRate":60,"port":4500,"token":"","retentionDays":2,"cronJob":"","urlCallback":"","thresholds":{"cpu":0,"memory":0}},"containers":{"refreshRate":60,"services":{"include":[],"exclude":[]}}}`]
- cleanupCacheApplications boolean [not null, default: false]
- cleanupCacheOnPreviews boolean [not null, default: false]
- cleanupCacheOnCompose boolean [not null, default: false]
- stripeCustomerId text
- stripeSubscriptionId text
- serversQuantity integer [not null, default: 0]
-}
-
-table verification {
- id text [pk, not null]
- identifier text [not null]
- value text [not null]
- expires_at timestamp [not null]
- created_at timestamp
- updated_at timestamp
-}
-
-ref: mount.applicationId > application.applicationId
-
-ref: mount.postgresId > postgres.postgresId
-
-ref: mount.mariadbId > mariadb.mariadbId
-
-ref: mount.mongoId > mongo.mongoId
-
-ref: mount.mysqlId > mysql.mysqlId
-
-ref: mount.redisId > redis.redisId
-
-ref: mount.composeId > compose.composeId
-
-ref: application.projectId > project.projectId
-
-ref: application.customGitSSHKeyId > "ssh-key".sshKeyId
-
-ref: application.registryId > registry.registryId
-
-ref: application.githubId - github.githubId
-
-ref: application.gitlabId - gitlab.gitlabId
-
-ref: application.bitbucketId - bitbucket.bitbucketId
-
-ref: application.serverId > server.serverId
-
-ref: backup.destinationId > destination.destinationId
-
-ref: backup.postgresId > postgres.postgresId
-
-ref: backup.mariadbId > mariadb.mariadbId
-
-ref: backup.mysqlId > mysql.mysqlId
-
-ref: backup.mongoId > mongo.mongoId
-
-ref: git_provider.gitProviderId - bitbucket.gitProviderId
-
-ref: certificate.serverId > server.serverId
-
-ref: certificate.userId - user.id
-
-ref: compose.projectId > project.projectId
-
-ref: compose.customGitSSHKeyId > "ssh-key".sshKeyId
-
-ref: compose.githubId - github.githubId
-
-ref: compose.gitlabId - gitlab.gitlabId
-
-ref: compose.bitbucketId - bitbucket.bitbucketId
-
-ref: compose.serverId > server.serverId
-
-ref: deployment.applicationId > application.applicationId
-
-ref: deployment.composeId > compose.composeId
-
-ref: deployment.serverId > server.serverId
-
-ref: deployment.previewDeploymentId > preview_deployments.previewDeploymentId
-
-ref: destination.userId - user.id
-
-ref: domain.applicationId > application.applicationId
-
-ref: domain.composeId > compose.composeId
-
-ref: preview_deployments.domainId - domain.domainId
-
-ref: github.gitProviderId - git_provider.gitProviderId
-
-ref: gitlab.gitProviderId - git_provider.gitProviderId
-
-ref: git_provider.userId - user.id
-
-ref: mariadb.projectId > project.projectId
-
-ref: mariadb.serverId > server.serverId
-
-ref: mongo.projectId > project.projectId
-
-ref: mongo.serverId > server.serverId
-
-ref: mysql.projectId > project.projectId
-
-ref: mysql.serverId > server.serverId
-
-ref: notification.slackId - slack.slackId
-
-ref: notification.telegramId - telegram.telegramId
-
-ref: notification.discordId - discord.discordId
-
-ref: notification.emailId - email.emailId
-
-ref: notification.gotifyId - gotify.gotifyId
-
-ref: notification.userId - user.id
-
-ref: port.applicationId > application.applicationId
-
-ref: postgres.projectId > project.projectId
-
-ref: postgres.serverId > server.serverId
-
-ref: preview_deployments.applicationId > application.applicationId
-
-ref: project.userId - user.id
-
-ref: redirect.applicationId > application.applicationId
-
-ref: redis.projectId > project.projectId
-
-ref: redis.serverId > server.serverId
-
-ref: registry.userId - user.id
-
-ref: security.applicationId > application.applicationId
-
-ref: server.userId - user.id
-
-ref: server.sshKeyId > "ssh-key".sshKeyId
-
-ref: "ssh-key".userId - user.id
\ No newline at end of file
diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts
index 26bb4632..a9c8da6e 100644
--- a/packages/server/src/db/schema/server.ts
+++ b/packages/server/src/db/schema/server.ts
@@ -1,16 +1,10 @@
import { relations } from "drizzle-orm";
-import {
- boolean,
- integer,
- jsonb,
- pgEnum,
- pgTable,
- text,
-} from "drizzle-orm/pg-core";
+import { boolean, integer, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
-import { organization } from "./account";
+
+import { admins } from "./admin";
import { applications } from "./application";
import { certificates } from "./certificate";
import { compose } from "./compose";
@@ -39,64 +33,24 @@ export const server = pgTable("server", {
.notNull()
.$defaultFn(() => generateAppName("server")),
enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
- createdAt: text("createdAt").notNull(),
- organizationId: text("organizationId")
+ createdAt: text("createdAt")
.notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
+ .$defaultFn(() => new Date().toISOString()),
+ adminId: text("adminId")
+ .notNull()
+ .references(() => admins.adminId, { onDelete: "cascade" }),
serverStatus: serverStatus("serverStatus").notNull().default("active"),
command: text("command").notNull().default(""),
sshKeyId: text("sshKeyId").references(() => sshKeys.sshKeyId, {
onDelete: "set null",
}),
- metricsConfig: jsonb("metricsConfig")
- .$type<{
- server: {
- type: "Dokploy" | "Remote";
- refreshRate: number;
- port: number;
- token: string;
- urlCallback: string;
- retentionDays: number;
- cronJob: string;
- thresholds: {
- cpu: number;
- memory: number;
- };
- };
- containers: {
- refreshRate: number;
- services: {
- include: string[];
- exclude: string[];
- };
- };
- }>()
- .notNull()
- .default({
- server: {
- type: "Remote",
- refreshRate: 60,
- port: 4500,
- token: "",
- urlCallback: "",
- cronJob: "",
- retentionDays: 2,
- thresholds: {
- cpu: 0,
- memory: 0,
- },
- },
- containers: {
- refreshRate: 60,
- services: {
- include: [],
- exclude: [],
- },
- },
- }),
});
export const serverRelations = relations(server, ({ one, many }) => ({
+ admin: one(admins, {
+ fields: [server.adminId],
+ references: [admins.adminId],
+ }),
deployments: many(deployments),
sshKey: one(sshKeys, {
fields: [server.sshKeyId],
@@ -110,10 +64,6 @@ export const serverRelations = relations(server, ({ one, many }) => ({
mysql: many(mysql),
postgres: many(postgres),
certificates: many(certificates),
- organization: one(organization, {
- fields: [server.organizationId],
- references: [organization.id],
- }),
}));
const createSchema = createInsertSchema(server, {
@@ -159,34 +109,3 @@ export const apiUpdateServer = createSchema
.extend({
command: z.string().optional(),
});
-
-export const apiUpdateServerMonitoring = createSchema
- .pick({
- serverId: true,
- })
- .required()
- .extend({
- metricsConfig: z
- .object({
- server: z.object({
- refreshRate: z.number().min(2),
- port: z.number().min(1),
- token: z.string(),
- urlCallback: z.string().url(),
- retentionDays: z.number().min(1),
- cronJob: z.string().min(1),
- thresholds: z.object({
- cpu: z.number().min(0),
- memory: z.number().min(0),
- }),
- }),
- containers: z.object({
- refreshRate: z.number().min(2),
- services: z.object({
- include: z.array(z.string()).optional(),
- exclude: z.array(z.string()).optional(),
- }),
- }),
- })
- .required(),
- });
diff --git a/packages/server/src/db/schema/session.ts b/packages/server/src/db/schema/session.ts
index f7c12dae..1b6d8cc1 100644
--- a/packages/server/src/db/schema/session.ts
+++ b/packages/server/src/db/schema/session.ts
@@ -1,18 +1,13 @@
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
-import { users_temp } from "./user";
+import { auth } from "./auth";
-// OLD TABLE
-export const session = pgTable("session_temp", {
+export const sessionTable = pgTable("session", {
id: text("id").primaryKey(),
- expiresAt: timestamp("expires_at").notNull(),
- token: text("token").notNull().unique(),
- createdAt: timestamp("created_at").notNull(),
- updatedAt: timestamp("updated_at").notNull(),
- ipAddress: text("ip_address"),
- userAgent: text("user_agent"),
userId: text("user_id")
.notNull()
- .references(() => users_temp.id, { onDelete: "cascade" }),
- impersonatedBy: text("impersonated_by"),
- activeOrganizationId: text("active_organization_id"),
+ .references(() => auth.id, { onDelete: "cascade" }),
+ expiresAt: timestamp("expires_at", {
+ withTimezone: true,
+ mode: "date",
+ }).notNull(),
});
diff --git a/packages/server/src/db/schema/source.ts b/packages/server/src/db/schema/source.ts
new file mode 100644
index 00000000..6618ced7
--- /dev/null
+++ b/packages/server/src/db/schema/source.ts
@@ -0,0 +1,27 @@
+import { pgTable, text } from "drizzle-orm/pg-core";
+import { createInsertSchema } from "drizzle-zod";
+import { nanoid } from "nanoid";
+import { z } from "zod";
+
+export const source = pgTable("project", {
+ projectId: text("projectId")
+ .notNull()
+ .primaryKey()
+ .$defaultFn(() => nanoid()),
+ name: text("name").notNull(),
+ description: text("description"),
+ createdAt: text("createdAt")
+ .notNull()
+ .$defaultFn(() => new Date().toISOString()),
+});
+
+const createSchema = createInsertSchema(source, {
+ name: z.string().min(1),
+ description: z.string(),
+ projectId: z.string(),
+});
+
+export const apiCreate = createSchema.pick({
+ name: true,
+ description: true,
+});
diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts
index 8a66d6d9..e4842851 100644
--- a/packages/server/src/db/schema/ssh-key.ts
+++ b/packages/server/src/db/schema/ssh-key.ts
@@ -3,7 +3,7 @@ import { pgTable, text } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { sshKeyCreate, sshKeyType } from "../validations";
-import { organization } from "./account";
+import { admins } from "./admin";
import { applications } from "./application";
import { compose } from "./compose";
import { server } from "./server";
@@ -21,18 +21,18 @@ export const sshKeys = pgTable("ssh-key", {
.notNull()
.$defaultFn(() => new Date().toISOString()),
lastUsedAt: text("lastUsedAt"),
- organizationId: text("organizationId")
- .notNull()
- .references(() => organization.id, { onDelete: "cascade" }),
+ adminId: text("adminId").references(() => admins.adminId, {
+ onDelete: "cascade",
+ }),
});
export const sshKeysRelations = relations(sshKeys, ({ many, one }) => ({
applications: many(applications),
compose: many(compose),
servers: many(server),
- organization: one(organization, {
- fields: [sshKeys.organizationId],
- references: [organization.id],
+ admin: one(admins, {
+ fields: [sshKeys.adminId],
+ references: [admins.adminId],
}),
}));
@@ -48,7 +48,7 @@ export const apiCreateSshKey = createSchema
description: true,
privateKey: true,
publicKey: true,
- organizationId: true,
+ adminId: true,
})
.merge(sshKeyCreate.pick({ privateKey: true }));
diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts
index 9307127a..735898f9 100644
--- a/packages/server/src/db/schema/user.ts
+++ b/packages/server/src/db/schema/user.ts
@@ -1,18 +1,10 @@
-import { relations } from "drizzle-orm";
-import {
- boolean,
- integer,
- jsonb,
- pgTable,
- text,
- timestamp,
-} from "drizzle-orm/pg-core";
+import { relations, sql } from "drizzle-orm";
+import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
-import { account, organization, apikey } from "./account";
-import { projects } from "./project";
-import { certificateType } from "./shared";
+import { admins } from "./admin";
+import { auth } from "./auth";
/**
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
* database instance for multiple projects.
@@ -20,115 +12,75 @@ import { certificateType } from "./shared";
* @see https://orm.drizzle.team/docs/goodies#multi-project-schema
*/
-// OLD TABLE
-
-// TEMP
-export const users_temp = pgTable("user_temp", {
- id: text("id")
+export const users = pgTable("user", {
+ userId: text("userId")
.notNull()
.primaryKey()
.$defaultFn(() => nanoid()),
- name: text("name").notNull().default(""),
+
+ token: text("token").notNull(),
isRegistered: boolean("isRegistered").notNull().default(false),
- expirationDate: text("expirationDate")
+ expirationDate: timestamp("expirationDate", {
+ precision: 3,
+ mode: "string",
+ }).notNull(),
+ createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
- createdAt2: text("createdAt")
- .notNull()
- .$defaultFn(() => new Date().toISOString()),
- createdAt: timestamp("created_at").defaultNow(),
- // Auth
- twoFactorEnabled: boolean("two_factor_enabled"),
- email: text("email").notNull().unique(),
- emailVerified: boolean("email_verified").notNull(),
- image: text("image"),
- banned: boolean("banned"),
- banReason: text("ban_reason"),
- banExpires: timestamp("ban_expires"),
- updatedAt: timestamp("updated_at").notNull(),
- // Admin
- serverIp: text("serverIp"),
- certificateType: certificateType("certificateType").notNull().default("none"),
- host: text("host"),
- letsEncryptEmail: text("letsEncryptEmail"),
- sshPrivateKey: text("sshPrivateKey"),
- enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
- enableLogRotation: boolean("enableLogRotation").notNull().default(false),
- // Metrics
- enablePaidFeatures: boolean("enablePaidFeatures").notNull().default(false),
- metricsConfig: jsonb("metricsConfig")
- .$type<{
- server: {
- type: "Dokploy" | "Remote";
- refreshRate: number;
- port: number;
- token: string;
- urlCallback: string;
- retentionDays: number;
- cronJob: string;
- thresholds: {
- cpu: number;
- memory: number;
- };
- };
- containers: {
- refreshRate: number;
- services: {
- include: string[];
- exclude: string[];
- };
- };
- }>()
- .notNull()
- .default({
- server: {
- type: "Dokploy",
- refreshRate: 60,
- port: 4500,
- token: "",
- retentionDays: 2,
- cronJob: "",
- urlCallback: "",
- thresholds: {
- cpu: 0,
- memory: 0,
- },
- },
- containers: {
- refreshRate: 60,
- services: {
- include: [],
- exclude: [],
- },
- },
- }),
- cleanupCacheApplications: boolean("cleanupCacheApplications")
+ canCreateProjects: boolean("canCreateProjects").notNull().default(false),
+ canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false),
+ canCreateServices: boolean("canCreateServices").notNull().default(false),
+ canDeleteProjects: boolean("canDeleteProjects").notNull().default(false),
+ canDeleteServices: boolean("canDeleteServices").notNull().default(false),
+ canAccessToDocker: boolean("canAccessToDocker").notNull().default(false),
+ canAccessToAPI: boolean("canAccessToAPI").notNull().default(false),
+ canAccessToGitProviders: boolean("canAccessToGitProviders")
.notNull()
.default(false),
- cleanupCacheOnPreviews: boolean("cleanupCacheOnPreviews")
+ canAccessToTraefikFiles: boolean("canAccessToTraefikFiles")
.notNull()
.default(false),
- cleanupCacheOnCompose: boolean("cleanupCacheOnCompose")
+ accessedProjects: text("accesedProjects")
+ .array()
.notNull()
- .default(false),
- stripeCustomerId: text("stripeCustomerId"),
- stripeSubscriptionId: text("stripeSubscriptionId"),
- serversQuantity: integer("serversQuantity").notNull().default(0),
+ .default(sql`ARRAY[]::text[]`),
+ accessedServices: text("accesedServices")
+ .array()
+ .notNull()
+ .default(sql`ARRAY[]::text[]`),
+ adminId: text("adminId")
+ .notNull()
+ .references(() => admins.adminId, { onDelete: "cascade" }),
+ authId: text("authId")
+ .notNull()
+ .references(() => auth.id, { onDelete: "cascade" }),
});
-export const usersRelations = relations(users_temp, ({ one, many }) => ({
- account: one(account, {
- fields: [users_temp.id],
- references: [account.userId],
+export const usersRelations = relations(users, ({ one }) => ({
+ auth: one(auth, {
+ fields: [users.authId],
+ references: [auth.id],
+ }),
+ admin: one(admins, {
+ fields: [users.adminId],
+ references: [admins.adminId],
}),
- organizations: many(organization),
- projects: many(projects),
- apiKeys: many(apikey),
}));
-const createSchema = createInsertSchema(users_temp, {
- id: z.string().min(1),
+const createSchema = createInsertSchema(users, {
+ userId: z.string().min(1),
+ authId: z.string().min(1),
+ token: z.string().min(1),
isRegistered: z.boolean().optional(),
+ adminId: z.string(),
+ accessedProjects: z.array(z.string()).optional(),
+ accessedServices: z.array(z.string()).optional(),
+ canCreateProjects: z.boolean().optional(),
+ canCreateServices: z.boolean().optional(),
+ canDeleteProjects: z.boolean().optional(),
+ canDeleteServices: z.boolean().optional(),
+ canAccessToDocker: z.boolean().optional(),
+ canAccessToTraefikFiles: z.boolean().optional(),
});
export const apiCreateUserInvitation = createSchema.pick({}).extend({
@@ -137,172 +89,41 @@ export const apiCreateUserInvitation = createSchema.pick({}).extend({
export const apiRemoveUser = createSchema
.pick({
- id: true,
+ authId: true,
})
.required();
export const apiFindOneToken = createSchema
- .pick({})
- .required()
- .extend({
- token: z.string().min(1),
- });
+ .pick({
+ token: true,
+ })
+ .required();
export const apiAssignPermissions = createSchema
.pick({
- id: true,
- // canCreateProjects: true,
- // canCreateServices: true,
- // canDeleteProjects: true,
- // canDeleteServices: true,
- // accessedProjects: true,
- // accessedServices: true,
- // canAccessToTraefikFiles: true,
- // canAccessToDocker: true,
- // canAccessToAPI: true,
- // canAccessToSSHKeys: true,
- // canAccessToGitProviders: true,
- })
- .extend({
- accessedProjects: z.array(z.string()).optional(),
- accessedServices: z.array(z.string()).optional(),
- canCreateProjects: z.boolean().optional(),
- canCreateServices: z.boolean().optional(),
- canDeleteProjects: z.boolean().optional(),
- canDeleteServices: z.boolean().optional(),
- canAccessToDocker: z.boolean().optional(),
- canAccessToTraefikFiles: z.boolean().optional(),
- canAccessToAPI: z.boolean().optional(),
- canAccessToSSHKeys: z.boolean().optional(),
- canAccessToGitProviders: z.boolean().optional(),
+ userId: true,
+ canCreateProjects: true,
+ canCreateServices: true,
+ canDeleteProjects: true,
+ canDeleteServices: true,
+ accessedProjects: true,
+ accessedServices: true,
+ canAccessToTraefikFiles: true,
+ canAccessToDocker: true,
+ canAccessToAPI: true,
+ canAccessToSSHKeys: true,
+ canAccessToGitProviders: true,
})
.required();
export const apiFindOneUser = createSchema
.pick({
- id: true,
+ userId: true,
})
.required();
export const apiFindOneUserByAuth = createSchema
.pick({
- // authId: true,
+ authId: true,
})
.required();
-export const apiSaveSSHKey = createSchema
- .pick({
- sshPrivateKey: true,
- })
- .required();
-
-export const apiAssignDomain = createSchema
- .pick({
- host: true,
- certificateType: true,
- letsEncryptEmail: true,
- })
- .required()
- .partial({
- letsEncryptEmail: true,
- });
-
-export const apiUpdateDockerCleanup = createSchema
- .pick({
- enableDockerCleanup: true,
- })
- .required()
- .extend({
- serverId: z.string().optional(),
- });
-
-export const apiTraefikConfig = z.object({
- traefikConfig: z.string().min(1),
-});
-
-export const apiModifyTraefikConfig = z.object({
- path: z.string().min(1),
- traefikConfig: z.string().min(1),
- serverId: z.string().optional(),
-});
-export const apiReadTraefikConfig = z.object({
- path: z.string().min(1),
- serverId: z.string().optional(),
-});
-
-export const apiEnableDashboard = z.object({
- enableDashboard: z.boolean().optional(),
- serverId: z.string().optional(),
-});
-
-export const apiServerSchema = z
- .object({
- serverId: z.string().optional(),
- })
- .optional();
-
-export const apiReadStatsLogs = z.object({
- page: z
- .object({
- pageIndex: z.number(),
- pageSize: z.number(),
- })
- .optional(),
- status: z.string().array().optional(),
- search: z.string().optional(),
- sort: z.object({ id: z.string(), desc: z.boolean() }).optional(),
-});
-
-export const apiUpdateWebServerMonitoring = z.object({
- metricsConfig: z
- .object({
- server: z.object({
- refreshRate: z.number().min(2),
- port: z.number().min(1),
- token: z.string(),
- urlCallback: z.string().url(),
- retentionDays: z.number().min(1),
- cronJob: z.string().min(1),
- thresholds: z.object({
- cpu: z.number().min(0),
- memory: z.number().min(0),
- }),
- }),
- containers: z.object({
- refreshRate: z.number().min(2),
- services: z.object({
- include: z.array(z.string()).optional(),
- exclude: z.array(z.string()).optional(),
- }),
- }),
- })
- .required(),
-});
-
-export const apiUpdateUser = createSchema.partial().extend({
- password: z.string().optional(),
- currentPassword: z.string().optional(),
- metricsConfig: z
- .object({
- server: z.object({
- type: z.enum(["Dokploy", "Remote"]),
- refreshRate: z.number(),
- port: z.number(),
- token: z.string(),
- urlCallback: z.string(),
- retentionDays: z.number(),
- cronJob: z.string(),
- thresholds: z.object({
- cpu: z.number(),
- memory: z.number(),
- }),
- }),
- containers: z.object({
- refreshRate: z.number(),
- services: z.object({
- include: z.array(z.string()),
- exclude: z.array(z.string()),
- }),
- }),
- })
- .optional(),
-});
diff --git a/packages/server/src/emails/emails/build-failed.tsx b/packages/server/src/emails/emails/build-failed.tsx
index 79e7b718..b3d99919 100644
--- a/packages/server/src/emails/emails/build-failed.tsx
+++ b/packages/server/src/emails/emails/build-failed.tsx
@@ -12,6 +12,7 @@ import {
Tailwind,
Text,
} from "@react-email/components";
+import * as React from "react";
export type TemplateProps = {
projectName: string;
diff --git a/packages/server/src/emails/emails/build-success.tsx b/packages/server/src/emails/emails/build-success.tsx
index d9e500ab..eadf7c44 100644
--- a/packages/server/src/emails/emails/build-success.tsx
+++ b/packages/server/src/emails/emails/build-success.tsx
@@ -12,6 +12,7 @@ import {
Tailwind,
Text,
} from "@react-email/components";
+import * as React from "react";
export type TemplateProps = {
projectName: string;
diff --git a/packages/server/src/emails/emails/database-backup.tsx b/packages/server/src/emails/emails/database-backup.tsx
index 754d4d98..2bdf944c 100644
--- a/packages/server/src/emails/emails/database-backup.tsx
+++ b/packages/server/src/emails/emails/database-backup.tsx
@@ -10,6 +10,7 @@ import {
Tailwind,
Text,
} from "@react-email/components";
+import * as React from "react";
export type TemplateProps = {
projectName: string;
diff --git a/packages/server/src/emails/emails/docker-cleanup.tsx b/packages/server/src/emails/emails/docker-cleanup.tsx
index 985406ae..05d93ed7 100644
--- a/packages/server/src/emails/emails/docker-cleanup.tsx
+++ b/packages/server/src/emails/emails/docker-cleanup.tsx
@@ -1,5 +1,6 @@
import {
Body,
+ Button,
Container,
Head,
Heading,
@@ -10,6 +11,7 @@ import {
Tailwind,
Text,
} from "@react-email/components";
+import * as React from "react";
export type TemplateProps = {
message: string;
diff --git a/packages/server/src/emails/emails/dokploy-restart.tsx b/packages/server/src/emails/emails/dokploy-restart.tsx
index db4edd69..1ad3d600 100644
--- a/packages/server/src/emails/emails/dokploy-restart.tsx
+++ b/packages/server/src/emails/emails/dokploy-restart.tsx
@@ -10,6 +10,7 @@ import {
Tailwind,
Text,
} from "@react-email/components";
+import * as React from "react";
export type TemplateProps = {
date: string;
diff --git a/packages/server/src/emails/emails/notion-magic-link.tsx b/packages/server/src/emails/emails/notion-magic-link.tsx
index f4071ce0..b2286c34 100644
--- a/packages/server/src/emails/emails/notion-magic-link.tsx
+++ b/packages/server/src/emails/emails/notion-magic-link.tsx
@@ -9,6 +9,7 @@ import {
Preview,
Text,
} from "@react-email/components";
+import * as React from "react";
interface NotionMagicLinkEmailProps {
loginCode?: string;
diff --git a/packages/server/src/emails/emails/plaid-verify-identity.tsx b/packages/server/src/emails/emails/plaid-verify-identity.tsx
index 88cf893d..650ab486 100644
--- a/packages/server/src/emails/emails/plaid-verify-identity.tsx
+++ b/packages/server/src/emails/emails/plaid-verify-identity.tsx
@@ -9,6 +9,7 @@ import {
Section,
Text,
} from "@react-email/components";
+import * as React from "react";
interface PlaidVerifyIdentityEmailProps {
validationCode?: string;
diff --git a/packages/server/src/emails/emails/stripe-welcome.tsx b/packages/server/src/emails/emails/stripe-welcome.tsx
index dbf02ea0..9377853b 100644
--- a/packages/server/src/emails/emails/stripe-welcome.tsx
+++ b/packages/server/src/emails/emails/stripe-welcome.tsx
@@ -11,6 +11,7 @@ import {
Section,
Text,
} from "@react-email/components";
+import * as React from "react";
const baseUrl = process.env.VERCEL_URL!;
diff --git a/packages/server/src/emails/emails/vercel-invite-user.tsx b/packages/server/src/emails/emails/vercel-invite-user.tsx
index 79f50cd7..53b31987 100644
--- a/packages/server/src/emails/emails/vercel-invite-user.tsx
+++ b/packages/server/src/emails/emails/vercel-invite-user.tsx
@@ -15,6 +15,7 @@ import {
Tailwind,
Text,
} from "@react-email/components";
+import * as React from "react";
interface VercelInviteUserEmailProps {
username?: string;
diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts
index f74b8d9d..d48e6ea8 100644
--- a/packages/server/src/index.ts
+++ b/packages/server/src/index.ts
@@ -1,4 +1,7 @@
+export * from "./auth/auth";
+export * from "./auth/token";
export * from "./auth/random-password";
+// export * from "./db";
export * from "./services/admin";
export * from "./services/user";
export * from "./services/project";
@@ -27,6 +30,7 @@ export * from "./services/ssh-key";
export * from "./services/git-provider";
export * from "./services/bitbucket";
export * from "./services/github";
+export * from "./services/auth";
export * from "./services/gitlab";
export * from "./services/server";
export * from "./services/application";
@@ -35,7 +39,6 @@ export * from "./setup/config-paths";
export * from "./setup/postgres-setup";
export * from "./setup/redis-setup";
export * from "./setup/server-setup";
-export * from "./setup/monitoring-setup";
export * from "./setup/setup";
export * from "./setup/traefik-setup";
export * from "./setup/server-validate";
@@ -54,7 +57,6 @@ export * from "./utils/notifications/database-backup";
export * from "./utils/notifications/dokploy-restart";
export * from "./utils/notifications/utils";
export * from "./utils/notifications/docker-cleanup";
-export * from "./utils/notifications/server-threshold";
export * from "./utils/builders/index";
export * from "./utils/builders/compose";
@@ -69,7 +71,6 @@ export * from "./utils/builders/utils";
export * from "./utils/cluster/upload";
export * from "./utils/docker/compose";
-export * from "./utils/docker/collision";
export * from "./utils/docker/domain";
export * from "./utils/docker/utils";
export * from "./utils/docker/types";
@@ -109,10 +110,8 @@ export * from "./utils/access-log/types";
export * from "./utils/access-log/utils";
export * from "./constants/index";
-export * from "./monitoring/utils";
+export * from "./monitoring/utilts";
export * from "./db/validations/domain";
export * from "./db/validations/index";
export * from "./utils/gpu-setup";
-
-export * from "./lib/auth";
diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts
deleted file mode 100644
index 1efa1730..00000000
--- a/packages/server/src/lib/auth.ts
+++ /dev/null
@@ -1,304 +0,0 @@
-import type { IncomingMessage } from "node:http";
-import * as bcrypt from "bcrypt";
-import { betterAuth } from "better-auth";
-import { drizzleAdapter } from "better-auth/adapters/drizzle";
-import { organization, twoFactor, apiKey } from "better-auth/plugins";
-import { and, desc, eq } from "drizzle-orm";
-import { db } from "../db";
-import * as schema from "../db/schema";
-import { sendEmail } from "../verification/send-verification-email";
-import { IS_CLOUD } from "../constants";
-
-const { handler, api } = betterAuth({
- database: drizzleAdapter(db, {
- provider: "pg",
- schema: schema,
- }),
- logger: {
- disabled: process.env.NODE_ENV === "production",
- },
- appName: "Dokploy",
- socialProviders: {
- github: {
- clientId: process.env.GITHUB_CLIENT_ID as string,
- clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
- },
- google: {
- clientId: process.env.GOOGLE_CLIENT_ID as string,
- clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
- },
- },
- emailVerification: {
- sendOnSignUp: true,
- autoSignInAfterVerification: true,
- sendVerificationEmail: async ({ user, url }) => {
- if (IS_CLOUD) {
- await sendEmail({
- email: user.email,
- subject: "Verify your email",
- text: `
- Click the link to verify your email: Verify Email
- `,
- });
- }
- },
- },
- emailAndPassword: {
- enabled: true,
- autoSignIn: !IS_CLOUD,
- requireEmailVerification: IS_CLOUD,
- password: {
- async hash(password) {
- return bcrypt.hashSync(password, 10);
- },
- async verify({ hash, password }) {
- return bcrypt.compareSync(password, hash);
- },
- },
- sendResetPassword: async ({ user, url }) => {
- await sendEmail({
- email: user.email,
- subject: "Reset your password",
- text: `
- Click the link to reset your password: Reset Password
- `,
- });
- },
- },
- databaseHooks: {
- user: {
- create: {
- after: async (user) => {
- const isAdminPresent = await db.query.member.findFirst({
- where: eq(schema.member.role, "owner"),
- });
-
- if (IS_CLOUD || !isAdminPresent) {
- await db.transaction(async (tx) => {
- const organization = await tx
- .insert(schema.organization)
- .values({
- name: "My Organization",
- ownerId: user.id,
- createdAt: new Date(),
- })
- .returning()
- .then((res) => res[0]);
-
- await tx.insert(schema.member).values({
- userId: user.id,
- organizationId: organization?.id || "",
- role: "owner",
- createdAt: new Date(),
- });
- });
- }
- },
- },
- },
- session: {
- create: {
- before: async (session) => {
- const member = await db.query.member.findFirst({
- where: eq(schema.member.userId, session.userId),
- orderBy: desc(schema.member.createdAt),
- with: {
- organization: true,
- },
- });
-
- return {
- data: {
- ...session,
- activeOrganizationId: member?.organization.id,
- },
- };
- },
- },
- },
- },
- user: {
- modelName: "users_temp",
- additionalFields: {
- role: {
- type: "string",
- // required: true,
- input: false,
- },
- ownerId: {
- type: "string",
- // required: true,
- input: false,
- },
- },
- },
-
- plugins: [
- apiKey({
- enableMetadata: true,
- }),
- twoFactor(),
- organization({
- async sendInvitationEmail(data, _request) {
- if (IS_CLOUD) {
- const host =
- process.env.NODE_ENV === "development"
- ? "http://localhost:3000"
- : "https://dokploy.com";
- const inviteLink = `${host}/invitation?token=${data.id}`;
-
- await sendEmail({
- email: data.email,
- subject: "Invitation to join organization",
- text: `
- You are invited to join ${data.organization.name} on Dokploy. Click the link to accept the invitation: Accept Invitation
- `,
- });
- }
- },
- }),
- ],
-});
-
-export const auth = {
- handler,
- createApiKey: api.createApiKey,
-};
-
-export const validateRequest = async (request: IncomingMessage) => {
- const apiKey = request.headers["x-api-key"] as string;
- if (apiKey) {
- try {
- const { valid, key, error } = await api.verifyApiKey({
- body: {
- key: apiKey,
- },
- });
-
- if (error) {
- throw new Error(error.message || "Error verifying API key");
- }
- if (!valid || !key) {
- return {
- session: null,
- user: null,
- };
- }
-
- const apiKeyRecord = await db.query.apikey.findFirst({
- where: eq(schema.apikey.id, key.id),
- with: {
- user: true,
- },
- });
-
- if (!apiKeyRecord) {
- return {
- session: null,
- user: null,
- };
- }
-
- const organizationId = JSON.parse(
- apiKeyRecord.metadata || "{}",
- ).organizationId;
-
- if (!organizationId) {
- return {
- session: null,
- user: null,
- };
- }
-
- const member = await db.query.member.findFirst({
- where: and(
- eq(schema.member.userId, apiKeyRecord.user.id),
- eq(schema.member.organizationId, organizationId),
- ),
- with: {
- organization: true,
- },
- });
-
- const {
- id,
- name,
- email,
- emailVerified,
- image,
- createdAt,
- updatedAt,
- twoFactorEnabled,
- } = apiKeyRecord.user;
-
- const mockSession = {
- session: {
- user: {
- id: apiKeyRecord.user.id,
- email: apiKeyRecord.user.email,
- name: apiKeyRecord.user.name,
- },
- activeOrganizationId: organizationId || "",
- },
- user: {
- id,
- name,
- email,
- emailVerified,
- image,
- createdAt,
- updatedAt,
- twoFactorEnabled,
- role: member?.role || "member",
- ownerId: member?.organization.ownerId || apiKeyRecord.user.id,
- },
- };
-
- return mockSession;
- } catch (error) {
- console.error("Error verifying API key", error);
- return {
- session: null,
- user: null,
- };
- }
- }
-
- // If no API key, proceed with normal session validation
- const session = await api.getSession({
- headers: new Headers({
- cookie: request.headers.cookie || "",
- }),
- });
-
- if (!session?.session || !session.user) {
- return {
- session: null,
- user: null,
- };
- }
-
- if (session?.user) {
- const member = await db.query.member.findFirst({
- where: and(
- eq(schema.member.userId, session.user.id),
- eq(
- schema.member.organizationId,
- session.session.activeOrganizationId || "",
- ),
- ),
- with: {
- organization: true,
- },
- });
-
- session.user.role = member?.role || "member";
- if (member) {
- session.user.ownerId = member.organization.ownerId;
- } else {
- session.user.ownerId = session.user.id;
- }
- }
-
- return session;
-};
diff --git a/packages/server/src/monitoring/utils.ts b/packages/server/src/monitoring/utilts.ts
similarity index 52%
rename from packages/server/src/monitoring/utils.ts
rename to packages/server/src/monitoring/utilts.ts
index 147ade0a..f67d5705 100644
--- a/packages/server/src/monitoring/utils.ts
+++ b/packages/server/src/monitoring/utilts.ts
@@ -1,19 +1,10 @@
import { promises } from "node:fs";
+import type Dockerode from "dockerode";
import osUtils from "node-os-utils";
import { paths } from "../constants";
-export interface Container {
- BlockIO: string;
- CPUPerc: string;
- Container: string;
- ID: string;
- MemPerc: string;
- MemUsage: string;
- Name: string;
- NetIO: string;
-}
export const recordAdvancedStats = async (
- stats: Container,
+ stats: Dockerode.ContainerStats,
appName: string,
) => {
const { MONITORING_PATH } = paths();
@@ -21,20 +12,29 @@ export const recordAdvancedStats = async (
await promises.mkdir(path, { recursive: true });
- await updateStatsFile(appName, "cpu", stats.CPUPerc);
- await updateStatsFile(appName, "memory", {
- used: stats.MemUsage.split(" ")[0],
- total: stats.MemUsage.split(" ")[2],
- });
+ const cpuPercent = calculateCpuUsagePercent(
+ stats.cpu_stats,
+ stats.precpu_stats,
+ );
+ const memoryStats = calculateMemoryStats(stats.memory_stats);
+ const blockIO = calculateBlockIO(stats.blkio_stats);
+ const networkUsage = calculateNetworkUsage(stats.networks);
+ await updateStatsFile(appName, "cpu", cpuPercent);
+ await updateStatsFile(appName, "memory", {
+ used: memoryStats.used,
+ free: memoryStats.free,
+ usedPercentage: memoryStats.usedPercentage,
+ total: memoryStats.total,
+ });
await updateStatsFile(appName, "block", {
- readMb: stats.BlockIO.split(" ")[0],
- writeMb: stats.BlockIO.split(" ")[2],
+ readMb: blockIO.readMb,
+ writeMb: blockIO.writeMb,
});
await updateStatsFile(appName, "network", {
- inputMb: stats.NetIO.split(" ")[0],
- outputMb: stats.NetIO.split(" ")[2],
+ inputMb: networkUsage.inputMb,
+ outputMb: networkUsage.outputMb,
});
if (appName === "dokploy") {
@@ -73,7 +73,7 @@ export const readStatsFile = async (
const filePath = `${MONITORING_PATH}/${appName}/${statType}.json`;
const data = await promises.readFile(filePath, "utf-8");
return JSON.parse(data);
- } catch (_error) {
+ } catch (error) {
return [];
}
};
@@ -108,7 +108,7 @@ export const readLastValueStatsFile = async (
const data = await promises.readFile(filePath, "utf-8");
const stats = JSON.parse(data);
return stats[stats.length - 1] || null;
- } catch (_error) {
+ } catch (error) {
return null;
}
};
@@ -122,3 +122,77 @@ export const getLastAdvancedStatsFile = async (appName: string) => {
block: await readLastValueStatsFile(appName, "block"),
};
};
+
+const calculateCpuUsagePercent = (
+ cpu_stats: Dockerode.ContainerStats["cpu_stats"],
+ precpu_stats: Dockerode.ContainerStats["precpu_stats"],
+) => {
+ const cpuDelta =
+ cpu_stats.cpu_usage.total_usage - precpu_stats.cpu_usage.total_usage;
+ const systemDelta =
+ cpu_stats.system_cpu_usage - precpu_stats.system_cpu_usage;
+
+ const numberCpus =
+ cpu_stats.online_cpus ||
+ (cpu_stats.cpu_usage.percpu_usage
+ ? cpu_stats.cpu_usage.percpu_usage.length
+ : 1);
+
+ if (systemDelta > 0 && cpuDelta > 0) {
+ return (cpuDelta / systemDelta) * numberCpus * 100.0;
+ }
+ return 0;
+};
+
+const calculateMemoryStats = (
+ memory_stats: Dockerode.ContainerStats["memory_stats"],
+) => {
+ const usedMemory = memory_stats.usage - (memory_stats.stats.cache || 0);
+ const availableMemory = memory_stats.limit;
+ const memoryUsedPercentage = (usedMemory / availableMemory) * 100.0;
+
+ return {
+ used: usedMemory,
+ free: availableMemory - usedMemory,
+ usedPercentage: memoryUsedPercentage,
+ total: availableMemory,
+ };
+};
+const calculateBlockIO = (
+ blkio_stats: Dockerode.ContainerStats["blkio_stats"],
+) => {
+ let readIO = 0;
+ let writeIO = 0;
+ if (blkio_stats?.io_service_bytes_recursive) {
+ for (const io of blkio_stats.io_service_bytes_recursive) {
+ if (io.op === "read") {
+ readIO += io.value;
+ } else if (io.op === "write") {
+ writeIO += io.value;
+ }
+ }
+ }
+ return {
+ readMb: readIO / (1024 * 1024),
+ writeMb: writeIO / (1024 * 1024),
+ };
+};
+
+const calculateNetworkUsage = (
+ networks: Dockerode.ContainerStats["networks"],
+) => {
+ let totalRx = 0;
+ let totalTx = 0;
+
+ const stats = Object.keys(networks);
+
+ for (const interfaceName of stats) {
+ const net = networks[interfaceName];
+ totalRx += net?.rx_bytes || 0;
+ totalTx += net?.tx_bytes || 0;
+ }
+ return {
+ inputMb: totalRx / (1024 * 1024),
+ outputMb: totalTx / (1024 * 1024),
+ };
+};
diff --git a/packages/server/src/services/admin.ts b/packages/server/src/services/admin.ts
index 3509868b..3502395e 100644
--- a/packages/server/src/services/admin.ts
+++ b/packages/server/src/services/admin.ts
@@ -1,56 +1,108 @@
+import { randomBytes } from "node:crypto";
import { db } from "@dokploy/server/db";
import {
- invitation,
- member,
- organization,
- users_temp,
+ admins,
+ type apiCreateUserInvitation,
+ auth,
+ users,
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
+import * as bcrypt from "bcrypt";
import { eq } from "drizzle-orm";
import { IS_CLOUD } from "../constants";
-export const findUserById = async (userId: string) => {
- const user = await db.query.users_temp.findFirst({
- where: eq(users_temp.id, userId),
- // with: {
- // account: true,
- // },
+export type Admin = typeof admins.$inferSelect;
+export const createInvitation = async (
+ input: typeof apiCreateUserInvitation._type,
+ adminId: string,
+) => {
+ await db.transaction(async (tx) => {
+ const result = await tx
+ .insert(auth)
+ .values({
+ email: input.email.toLowerCase(),
+ rol: "user",
+ password: bcrypt.hashSync("01231203012312", 10),
+ })
+ .returning()
+ .then((res) => res[0]);
+
+ if (!result) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Error creating the user",
+ });
+ }
+ const expiresIn24Hours = new Date();
+ expiresIn24Hours.setDate(expiresIn24Hours.getDate() + 1);
+ const token = randomBytes(32).toString("hex");
+ await tx
+ .insert(users)
+ .values({
+ adminId: adminId,
+ authId: result.id,
+ token,
+ expirationDate: expiresIn24Hours.toISOString(),
+ })
+ .returning();
});
- if (!user) {
- throw new TRPCError({
- code: "NOT_FOUND",
- message: "User not found",
- });
- }
- return user;
};
-export const findOrganizationById = async (organizationId: string) => {
- const organizationResult = await db.query.organization.findFirst({
- where: eq(organization.id, organizationId),
+export const findAdminById = async (adminId: string) => {
+ const admin = await db.query.admins.findFirst({
+ where: eq(admins.adminId, adminId),
});
- return organizationResult;
+ if (!admin) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Admin not found",
+ });
+ }
+ return admin;
+};
+
+export const updateAdmin = async (
+ authId: string,
+ adminData: Partial,
+) => {
+ const admin = await db
+ .update(admins)
+ .set({
+ ...adminData,
+ })
+ .where(eq(admins.authId, authId))
+ .returning()
+ .then((res) => res[0]);
+
+ return admin;
};
export const isAdminPresent = async () => {
- const admin = await db.query.member.findFirst({
- where: eq(member.role, "owner"),
- });
-
+ const admin = await db.query.admins.findFirst();
if (!admin) {
return false;
}
return true;
};
-export const findAdmin = async () => {
- const admin = await db.query.member.findFirst({
- where: eq(member.role, "owner"),
+export const findAdminByAuthId = async (authId: string) => {
+ const admin = await db.query.admins.findFirst({
+ where: eq(admins.authId, authId),
with: {
- user: true,
+ users: true,
},
});
+ if (!admin) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Admin not found",
+ });
+ }
+ return admin;
+};
+export const findAdmin = async () => {
+ const admin = await db.query.admins.findFirst({});
if (!admin) {
throw new TRPCError({
code: "NOT_FOUND",
@@ -61,15 +113,14 @@ export const findAdmin = async () => {
};
export const getUserByToken = async (token: string) => {
- const user = await db.query.invitation.findFirst({
- where: eq(invitation.id, token),
- columns: {
- id: true,
- email: true,
- status: true,
- expiresAt: true,
- role: true,
- inviterId: true,
+ const user = await db.query.users.findFirst({
+ where: eq(users.token, token),
+ with: {
+ auth: {
+ columns: {
+ password: false,
+ },
+ },
},
});
@@ -79,23 +130,34 @@ export const getUserByToken = async (token: string) => {
message: "Invitation not found",
});
}
-
- const userAlreadyExists = await db.query.users_temp.findFirst({
- where: eq(users_temp.email, user?.email || ""),
- });
-
- const { expiresAt, ...rest } = user;
return {
- ...rest,
- isExpired: user.expiresAt < new Date(),
- userAlreadyExists: !!userAlreadyExists,
+ ...user,
+ isExpired: user.isRegistered,
};
};
-export const removeUserById = async (userId: string) => {
+export const removeUserByAuthId = async (authId: string) => {
await db
- .delete(users_temp)
- .where(eq(users_temp.id, userId))
+ .delete(auth)
+ .where(eq(auth.id, authId))
+ .returning()
+ .then((res) => res[0]);
+};
+
+export const removeAdminByAuthId = async (authId: string) => {
+ const admin = await findAdminByAuthId(authId);
+ if (!admin) return null;
+
+ // First delete all associated users
+ const users = admin.users;
+
+ for (const user of users) {
+ await removeUserByAuthId(user.authId);
+ }
+ // Then delete the auth record which will cascade delete the admin
+ return await db
+ .delete(auth)
+ .where(eq(auth.id, authId))
.returning()
.then((res) => res[0]);
};
@@ -106,8 +168,8 @@ export const getDokployUrl = async () => {
}
const admin = await findAdmin();
- if (admin.user.host) {
- return `https://${admin.user.host}`;
+ if (admin.host) {
+ return `https://${admin.host}`;
}
- return `http://${admin.user.serverIp}:${process.env.PORT}`;
+ return `http://${admin.serverIp}:${process.env.PORT}`;
};
diff --git a/packages/server/src/services/application.ts b/packages/server/src/services/application.ts
index 425a6adb..8de9b5ba 100644
--- a/packages/server/src/services/application.ts
+++ b/packages/server/src/services/application.ts
@@ -4,8 +4,9 @@ import {
type apiCreateApplication,
applications,
buildAppName,
+ cleanAppName,
} from "@dokploy/server/db/schema";
-import { getAdvancedStats } from "@dokploy/server/monitoring/utils";
+import { getAdvancedStats } from "@dokploy/server/monitoring/utilts";
import {
buildApplication,
getBuildCommand,
@@ -27,6 +28,7 @@ import {
getCustomGitCloneCommand,
} from "@dokploy/server/utils/providers/git";
import {
+ authGithub,
cloneGithubRepository,
getGithubCloneCommand,
} from "@dokploy/server/utils/providers/github";
@@ -173,7 +175,6 @@ export const deployApplication = async ({
descriptionLog: string;
}) => {
const application = await findApplicationById(applicationId);
-
const buildLink = `${await getDokployUrl()}/dashboard/project/${application.projectId}/services/application/${application.applicationId}?tab=deployments`;
const deployment = await createDeployment({
applicationId: applicationId,
@@ -182,12 +183,6 @@ export const deployApplication = async ({
});
try {
- // const admin = await findUserById(application.project.userId);
-
- // if (admin.cleanupCacheApplications) {
- // await cleanupFullDocker(application?.serverId);
- // }
-
if (application.sourceType === "github") {
await cloneGithubRepository({
...application,
@@ -217,7 +212,7 @@ export const deployApplication = async ({
applicationName: application.name,
applicationType: "application",
buildLink,
- organizationId: application.project.organizationId,
+ adminId: application.project.adminId,
domains: application.domains,
});
} catch (error) {
@@ -230,7 +225,7 @@ export const deployApplication = async ({
// @ts-ignore
errorMessage: error?.message || "Error building",
buildLink,
- organizationId: application.project.organizationId,
+ adminId: application.project.adminId,
});
throw error;
@@ -249,7 +244,6 @@ export const rebuildApplication = async ({
descriptionLog: string;
}) => {
const application = await findApplicationById(applicationId);
-
const deployment = await createDeployment({
applicationId: applicationId,
title: titleLog,
@@ -257,11 +251,6 @@ export const rebuildApplication = async ({
});
try {
- // const admin = await findUserById(application.project.userId);
-
- // if (admin.cleanupCacheApplications) {
- // await cleanupFullDocker(application?.serverId);
- // }
if (application.sourceType === "github") {
await buildApplication(application, deployment.logPath);
} else if (application.sourceType === "gitlab") {
@@ -296,7 +285,6 @@ export const deployRemoteApplication = async ({
descriptionLog: string;
}) => {
const application = await findApplicationById(applicationId);
-
const buildLink = `${await getDokployUrl()}/dashboard/project/${application.projectId}/services/application/${application.applicationId}?tab=deployments`;
const deployment = await createDeployment({
applicationId: applicationId,
@@ -306,11 +294,6 @@ export const deployRemoteApplication = async ({
try {
if (application.serverId) {
- // const admin = await findUserById(application.project.userId);
-
- // if (admin.cleanupCacheApplications) {
- // await cleanupFullDocker(application?.serverId);
- // }
let command = "set -e;";
if (application.sourceType === "github") {
command += await getGithubCloneCommand({
@@ -349,7 +332,7 @@ export const deployRemoteApplication = async ({
applicationName: application.name,
applicationType: "application",
buildLink,
- organizationId: application.project.organizationId,
+ adminId: application.project.adminId,
domains: application.domains,
});
} catch (error) {
@@ -373,9 +356,17 @@ export const deployRemoteApplication = async ({
// @ts-ignore
errorMessage: error?.message || "Error building",
buildLink,
- organizationId: application.project.organizationId,
+ adminId: application.project.adminId,
});
+ console.log(
+ "Error on ",
+ application.buildType,
+ "/",
+ application.sourceType,
+ error,
+ );
+
throw error;
}
@@ -394,7 +385,6 @@ export const deployPreviewApplication = async ({
previewDeploymentId: string;
}) => {
const application = await findApplicationById(applicationId);
-
const deployment = await createDeploymentPreview({
title: titleLog,
description: descriptionLog,
@@ -448,15 +438,9 @@ export const deployPreviewApplication = async ({
body: `### Dokploy Preview Deployment\n\n${buildingComment}`,
});
application.appName = previewDeployment.appName;
- application.env = `${application.previewEnv}\nDOKPLOY_DEPLOY_URL=${previewDeployment?.domain}`;
+ application.env = application.previewEnv;
application.buildArgs = application.previewBuildArgs;
- // const admin = await findUserById(application.project.userId);
-
- // if (admin.cleanupCacheOnPreviews) {
- // await cleanupFullDocker(application?.serverId);
- // }
-
if (application.sourceType === "github") {
await cloneGithubRepository({
...application,
@@ -466,6 +450,7 @@ export const deployPreviewApplication = async ({
});
await buildApplication(application, deployment.logPath);
}
+ // 4eef09efc46009187d668cf1c25f768d0bde4f91
const successComment = getIssueComment(
application.name,
"success",
@@ -507,7 +492,6 @@ export const deployRemotePreviewApplication = async ({
previewDeploymentId: string;
}) => {
const application = await findApplicationById(applicationId);
-
const deployment = await createDeploymentPreview({
title: titleLog,
description: descriptionLog,
@@ -561,21 +545,14 @@ export const deployRemotePreviewApplication = async ({
body: `### Dokploy Preview Deployment\n\n${buildingComment}`,
});
application.appName = previewDeployment.appName;
- application.env = `${application.previewEnv}\nDOKPLOY_DEPLOY_URL=${previewDeployment?.domain}`;
+ application.env = application.previewEnv;
application.buildArgs = application.previewBuildArgs;
if (application.serverId) {
- // const admin = await findUserById(application.project.userId);
-
- // if (admin.cleanupCacheOnPreviews) {
- // await cleanupFullDocker(application?.serverId);
- // }
let command = "set -e;";
if (application.sourceType === "github") {
command += await getGithubCloneCommand({
...application,
- appName: previewDeployment.appName,
- branch: previewDeployment.branch,
serverId: application.serverId,
logPath: deployment.logPath,
});
@@ -625,7 +602,6 @@ export const rebuildRemoteApplication = async ({
descriptionLog: string;
}) => {
const application = await findApplicationById(applicationId);
-
const deployment = await createDeployment({
applicationId: applicationId,
title: titleLog,
@@ -634,11 +610,6 @@ export const rebuildRemoteApplication = async ({
try {
if (application.serverId) {
- // const admin = await findUserById(application.project.userId);
-
- // if (admin.cleanupCacheApplications) {
- // await cleanupFullDocker(application?.serverId);
- // }
if (application.sourceType !== "docker") {
let command = "set -e;";
command += getBuildCommand(application, deployment.logPath);
diff --git a/packages/server/src/services/auth.ts b/packages/server/src/services/auth.ts
new file mode 100644
index 00000000..65a01c41
--- /dev/null
+++ b/packages/server/src/services/auth.ts
@@ -0,0 +1,184 @@
+import { randomBytes } from "node:crypto";
+import { db } from "@dokploy/server/db";
+import {
+ admins,
+ type apiCreateAdmin,
+ type apiCreateUser,
+ auth,
+ users,
+} from "@dokploy/server/db/schema";
+import { getPublicIpWithFallback } from "@dokploy/server/wss/utils";
+import { TRPCError } from "@trpc/server";
+import * as bcrypt from "bcrypt";
+import { eq } from "drizzle-orm";
+import encode from "hi-base32";
+import { TOTP } from "otpauth";
+import QRCode from "qrcode";
+import { IS_CLOUD } from "../constants";
+
+export type Auth = typeof auth.$inferSelect;
+
+export const createAdmin = async (input: typeof apiCreateAdmin._type) => {
+ return await db.transaction(async (tx) => {
+ const hashedPassword = bcrypt.hashSync(input.password, 10);
+ const newAuth = await tx
+ .insert(auth)
+ .values({
+ email: input.email.toLowerCase(),
+ password: hashedPassword,
+ rol: "admin",
+ })
+ .returning()
+ .then((res) => res[0]);
+
+ if (!newAuth) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Error creating the user",
+ });
+ }
+
+ await tx
+ .insert(admins)
+ .values({
+ authId: newAuth.id,
+ ...(!IS_CLOUD && {
+ serverIp:
+ process.env.ADVERTISE_ADDR || (await getPublicIpWithFallback()),
+ }),
+ })
+ .returning();
+
+ return newAuth;
+ });
+};
+
+export const createUser = async (input: typeof apiCreateUser._type) => {
+ return await db.transaction(async (tx) => {
+ const hashedPassword = bcrypt.hashSync(input.password, 10);
+ const res = await tx
+ .update(auth)
+ .set({
+ password: hashedPassword,
+ })
+ .where(eq(auth.id, input.id))
+ .returning()
+ .then((res) => res[0]);
+
+ if (!res) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Error creating the user",
+ });
+ }
+
+ const user = await tx
+ .update(users)
+ .set({
+ isRegistered: true,
+ expirationDate: undefined,
+ })
+ .where(eq(users.token, input.token))
+ .returning()
+ .then((res) => res[0]);
+
+ return user;
+ });
+};
+
+export const findAuthByEmail = async (email: string) => {
+ const result = await db.query.auth.findFirst({
+ where: eq(auth.email, email),
+ });
+ if (!result) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "User not found",
+ });
+ }
+ return result;
+};
+
+export const findAuthById = async (authId: string) => {
+ const result = await db.query.auth.findFirst({
+ where: eq(auth.id, authId),
+ columns: {
+ password: false,
+ },
+ });
+ if (!result) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Auth not found",
+ });
+ }
+ return result;
+};
+
+export const updateAuthById = async (
+ authId: string,
+ authData: Partial,
+) => {
+ const result = await db
+ .update(auth)
+ .set({
+ ...authData,
+ })
+ .where(eq(auth.id, authId))
+ .returning();
+
+ return result[0];
+};
+
+export const generate2FASecret = async (authId: string) => {
+ const auth = await findAuthById(authId);
+
+ const base32_secret = generateBase32Secret();
+
+ const totp = new TOTP({
+ issuer: "Dokploy",
+ label: `${auth?.email}`,
+ algorithm: "SHA1",
+ digits: 6,
+ secret: base32_secret,
+ });
+
+ const otpauth_url = totp.toString();
+
+ const qrUrl = await QRCode.toDataURL(otpauth_url);
+
+ return {
+ qrCodeUrl: qrUrl,
+ secret: base32_secret,
+ };
+};
+
+export const verify2FA = async (
+ auth: Omit,
+ secret: string,
+ pin: string,
+) => {
+ const totp = new TOTP({
+ issuer: "Dokploy",
+ label: `${auth?.email}`,
+ algorithm: "SHA1",
+ digits: 6,
+ secret: secret,
+ });
+
+ const delta = totp.validate({ token: pin });
+
+ if (delta === null) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message: "Invalid 2FA code",
+ });
+ }
+ return auth;
+};
+
+const generateBase32Secret = () => {
+ const buffer = randomBytes(15);
+ const base32 = encode.encode(buffer).replace(/=/g, "").substring(0, 24);
+ return base32;
+};
diff --git a/packages/server/src/services/backup.ts b/packages/server/src/services/backup.ts
index 32705786..70e37af4 100644
--- a/packages/server/src/services/backup.ts
+++ b/packages/server/src/services/backup.ts
@@ -6,7 +6,7 @@ import { eq } from "drizzle-orm";
export type Backup = typeof backups.$inferSelect;
export type BackupSchedule = Awaited>;
-export type BackupScheduleList = Awaited>;
+
export const createBackup = async (input: typeof apiCreateBackup._type) => {
const newBackup = await db
.insert(backups)
@@ -69,20 +69,3 @@ export const removeBackupById = async (backupId: string) => {
return result[0];
};
-
-export const findBackupsByDbId = async (
- id: string,
- type: "postgres" | "mysql" | "mariadb" | "mongo",
-) => {
- const result = await db.query.backups.findMany({
- where: eq(backups[`${type}Id`], id),
- with: {
- postgres: true,
- mysql: true,
- mariadb: true,
- mongo: true,
- destination: true,
- },
- });
- return result || [];
-};
diff --git a/packages/server/src/services/bitbucket.ts b/packages/server/src/services/bitbucket.ts
index 7b5be7d6..21807156 100644
--- a/packages/server/src/services/bitbucket.ts
+++ b/packages/server/src/services/bitbucket.ts
@@ -12,14 +12,14 @@ export type Bitbucket = typeof bitbucket.$inferSelect;
export const createBitbucket = async (
input: typeof apiCreateBitbucket._type,
- organizationId: string,
+ adminId: string,
) => {
return await db.transaction(async (tx) => {
const newGitProvider = await tx
.insert(gitProvider)
.values({
providerType: "bitbucket",
- organizationId: organizationId,
+ adminId: adminId,
name: input.name,
})
.returning()
@@ -74,12 +74,12 @@ export const updateBitbucket = async (
.where(eq(bitbucket.bitbucketId, bitbucketId))
.returning();
- if (input.name || input.organizationId) {
+ if (input.name || input.adminId) {
await tx
.update(gitProvider)
.set({
name: input.name,
- organizationId: input.organizationId,
+ adminId: input.adminId,
})
.where(eq(gitProvider.gitProviderId, input.gitProviderId))
.returning();
diff --git a/packages/server/src/services/certificate.ts b/packages/server/src/services/certificate.ts
index f59f1c2a..23177862 100644
--- a/packages/server/src/services/certificate.ts
+++ b/packages/server/src/services/certificate.ts
@@ -33,13 +33,13 @@ export const findCertificateById = async (certificateId: string) => {
export const createCertificate = async (
certificateData: z.infer,
- organizationId: string,
+ adminId: string,
) => {
const certificate = await db
.insert(certificates)
.values({
...certificateData,
- organizationId: organizationId,
+ adminId: adminId,
})
.returning();
diff --git a/packages/server/src/services/compose.ts b/packages/server/src/services/compose.ts
index a3ebc26c..8561dd37 100644
--- a/packages/server/src/services/compose.ts
+++ b/packages/server/src/services/compose.ts
@@ -3,6 +3,7 @@ import { paths } from "@dokploy/server/constants";
import { db } from "@dokploy/server/db";
import { type apiCreateCompose, compose } from "@dokploy/server/db/schema";
import { buildAppName, cleanAppName } from "@dokploy/server/db/schema";
+import { generatePassword } from "@dokploy/server/templates/utils";
import {
buildCompose,
getBuildComposeCommand,
@@ -205,7 +206,6 @@ export const deployCompose = async ({
descriptionLog: string;
}) => {
const compose = await findComposeById(composeId);
-
const buildLink = `${await getDokployUrl()}/dashboard/project/${
compose.projectId
}/services/compose/${compose.composeId}?tab=deployments`;
@@ -216,10 +216,6 @@ export const deployCompose = async ({
});
try {
- // const admin = await findUserById(compose.project.userId);
- // if (admin.cleanupCacheOnCompose) {
- // await cleanupFullDocker(compose?.serverId);
- // }
if (compose.sourceType === "github") {
await cloneGithubRepository({
...compose,
@@ -246,7 +242,7 @@ export const deployCompose = async ({
applicationName: compose.name,
applicationType: "compose",
buildLink,
- organizationId: compose.project.organizationId,
+ adminId: compose.project.adminId,
domains: compose.domains,
});
} catch (error) {
@@ -261,7 +257,7 @@ export const deployCompose = async ({
// @ts-ignore
errorMessage: error?.message || "Error building",
buildLink,
- organizationId: compose.project.organizationId,
+ adminId: compose.project.adminId,
});
throw error;
}
@@ -277,7 +273,6 @@ export const rebuildCompose = async ({
descriptionLog: string;
}) => {
const compose = await findComposeById(composeId);
-
const deployment = await createDeploymentCompose({
composeId: composeId,
title: titleLog,
@@ -285,10 +280,6 @@ export const rebuildCompose = async ({
});
try {
- // const admin = await findUserById(compose.project.userId);
- // if (admin.cleanupCacheOnCompose) {
- // await cleanupFullDocker(compose?.serverId);
- // }
if (compose.serverId) {
await getBuildComposeCommand(compose, deployment.logPath);
} else {
@@ -320,7 +311,6 @@ export const deployRemoteCompose = async ({
descriptionLog: string;
}) => {
const compose = await findComposeById(composeId);
-
const buildLink = `${await getDokployUrl()}/dashboard/project/${
compose.projectId
}/services/compose/${compose.composeId}?tab=deployments`;
@@ -331,10 +321,6 @@ export const deployRemoteCompose = async ({
});
try {
if (compose.serverId) {
- // const admin = await findUserById(compose.project.userId);
- // if (admin.cleanupCacheOnCompose) {
- // await cleanupFullDocker(compose?.serverId);
- // }
let command = "set -e;";
if (compose.sourceType === "github") {
@@ -380,7 +366,7 @@ export const deployRemoteCompose = async ({
applicationName: compose.name,
applicationType: "compose",
buildLink,
- organizationId: compose.project.organizationId,
+ adminId: compose.project.adminId,
domains: compose.domains,
});
} catch (error) {
@@ -405,7 +391,7 @@ export const deployRemoteCompose = async ({
// @ts-ignore
errorMessage: error?.message || "Error building",
buildLink,
- organizationId: compose.project.organizationId,
+ adminId: compose.project.adminId,
});
throw error;
}
@@ -421,7 +407,6 @@ export const rebuildRemoteCompose = async ({
descriptionLog: string;
}) => {
const compose = await findComposeById(composeId);
-
const deployment = await createDeploymentCompose({
composeId: composeId,
title: titleLog,
@@ -429,10 +414,6 @@ export const rebuildRemoteCompose = async ({
});
try {
- // const admin = await findUserById(compose.project.userId);
- // if (admin.cleanupCacheOnCompose) {
- // await cleanupFullDocker(compose?.serverId);
- // }
if (compose.serverId) {
await getBuildComposeCommand(compose, deployment.logPath);
}
@@ -557,17 +538,6 @@ export const stopCompose = async (composeId: string) => {
}
}
- if (compose.composeType === "stack") {
- if (compose.serverId) {
- await execAsyncRemote(
- compose.serverId,
- `docker stack rm ${compose.appName}`,
- );
- } else {
- await execAsync(`docker stack rm ${compose.appName}`);
- }
- }
-
await updateCompose(composeId, {
composeStatus: "idle",
});
diff --git a/packages/server/src/services/deployment.ts b/packages/server/src/services/deployment.ts
index 86d6c88e..0e55ea32 100644
--- a/packages/server/src/services/deployment.ts
+++ b/packages/server/src/services/deployment.ts
@@ -12,7 +12,7 @@ import {
import { removeDirectoryIfExistsContent } from "@dokploy/server/utils/filesystem/directory";
import { TRPCError } from "@trpc/server";
import { format } from "date-fns";
-import { desc, eq } from "drizzle-orm";
+import { and, desc, eq, isNull } from "drizzle-orm";
import {
type Application,
findApplicationById,
@@ -98,17 +98,6 @@ export const createDeployment = async (
}
return deploymentCreate[0];
} catch (error) {
- await db
- .insert(deployments)
- .values({
- applicationId: deployment.applicationId,
- title: deployment.title || "Deployment",
- status: "error",
- logPath: "",
- description: deployment.description || "",
- errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`,
- })
- .returning();
await updateApplicationStatus(application.applicationId, "error");
console.log(error);
throw new TRPCError({
@@ -175,17 +164,6 @@ export const createDeploymentPreview = async (
}
return deploymentCreate[0];
} catch (error) {
- await db
- .insert(deployments)
- .values({
- previewDeploymentId: deployment.previewDeploymentId,
- title: deployment.title || "Deployment",
- status: "error",
- logPath: "",
- description: deployment.description || "",
- errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`,
- })
- .returning();
await updatePreviewDeployment(deployment.previewDeploymentId, {
previewStatus: "error",
});
@@ -248,17 +226,6 @@ echo "Initializing deployment" >> ${logFilePath};
}
return deploymentCreate[0];
} catch (error) {
- await db
- .insert(deployments)
- .values({
- composeId: deployment.composeId,
- title: deployment.title || "Deployment",
- status: "error",
- logPath: "",
- description: deployment.description || "",
- errorMessage: `An error have occured: ${error instanceof Error ? error.message : error}`,
- })
- .returning();
await updateCompose(compose.composeId, {
composeStatus: "error",
});
@@ -278,11 +245,9 @@ export const removeDeployment = async (deploymentId: string) => {
.returning();
return deployment[0];
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error creating the deployment";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error deleting this deployment",
});
}
};
@@ -537,11 +502,9 @@ export const createServerDeployment = async (
}
return deploymentCreate[0];
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error creating the deployment";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error creating the deployment",
});
}
};
diff --git a/packages/server/src/services/destination.ts b/packages/server/src/services/destination.ts
index e66f8695..892c9354 100644
--- a/packages/server/src/services/destination.ts
+++ b/packages/server/src/services/destination.ts
@@ -10,13 +10,13 @@ export type Destination = typeof destinations.$inferSelect;
export const createDestintation = async (
input: typeof apiCreateDestination._type,
- organizationId: string,
+ adminId: string,
) => {
const newDestination = await db
.insert(destinations)
.values({
...input,
- organizationId: organizationId,
+ adminId: adminId,
})
.returning()
.then((value) => value[0]);
@@ -46,14 +46,14 @@ export const findDestinationById = async (destinationId: string) => {
export const removeDestinationById = async (
destinationId: string,
- organizationId: string,
+ adminId: string,
) => {
const result = await db
.delete(destinations)
.where(
and(
eq(destinations.destinationId, destinationId),
- eq(destinations.organizationId, organizationId),
+ eq(destinations.adminId, adminId),
),
)
.returning();
@@ -73,7 +73,7 @@ export const updateDestinationById = async (
.where(
and(
eq(destinations.destinationId, destinationId),
- eq(destinations.organizationId, destinationData.organizationId || ""),
+ eq(destinations.adminId, destinationData.adminId || ""),
),
)
.returning();
diff --git a/packages/server/src/services/docker.ts b/packages/server/src/services/docker.ts
index a4a3b0b5..b7a5c440 100644
--- a/packages/server/src/services/docker.ts
+++ b/packages/server/src/services/docker.ts
@@ -58,11 +58,7 @@ export const getContainers = async (serverId?: string | null) => {
serverId,
};
})
- .filter(
- (container) =>
- !container.name.includes("dokploy") ||
- container.name.includes("dokploy-monitoring"),
- );
+ .filter((container) => !container.name.includes("dokploy"));
return containers;
} catch (error) {
@@ -98,7 +94,7 @@ export const getConfig = async (
const config = JSON.parse(stdout);
return config;
- } catch (_error) {}
+ } catch (error) {}
};
export const getContainersByAppNameMatch = async (
@@ -156,7 +152,7 @@ export const getContainersByAppNameMatch = async (
});
return containers || [];
- } catch (_error) {}
+ } catch (error) {}
return [];
};
@@ -214,7 +210,7 @@ export const getStackContainersByAppName = async (
});
return containers || [];
- } catch (_error) {}
+ } catch (error) {}
return [];
};
@@ -274,7 +270,7 @@ export const getServiceContainersByAppName = async (
});
return containers || [];
- } catch (_error) {}
+ } catch (error) {}
return [];
};
@@ -325,7 +321,7 @@ export const getContainersByAppLabel = async (
});
return containers || [];
- } catch (_error) {}
+ } catch (error) {}
return [];
};
@@ -344,7 +340,7 @@ export const containerRestart = async (containerId: string) => {
const config = JSON.parse(stdout);
return config;
- } catch (_error) {}
+ } catch (error) {}
};
export const getSwarmNodes = async (serverId?: string) => {
@@ -373,7 +369,7 @@ export const getSwarmNodes = async (serverId?: string) => {
.split("\n")
.map((line) => JSON.parse(line));
return nodesArray;
- } catch (_error) {}
+ } catch (error) {}
};
export const getNodeInfo = async (nodeId: string, serverId?: string) => {
@@ -399,7 +395,7 @@ export const getNodeInfo = async (nodeId: string, serverId?: string) => {
const nodeInfo = JSON.parse(stdout);
return nodeInfo;
- } catch (_error) {}
+ } catch (error) {}
};
export const getNodeApplications = async (serverId?: string) => {
@@ -431,7 +427,7 @@ export const getNodeApplications = async (serverId?: string) => {
.filter((service) => !service.Name.startsWith("dokploy-"));
return appArray;
- } catch (_error) {}
+ } catch (error) {}
};
export const getApplicationInfo = async (
@@ -464,5 +460,5 @@ export const getApplicationInfo = async (
.map((line) => JSON.parse(line));
return appArray;
- } catch (_error) {}
+ } catch (error) {}
};
diff --git a/packages/server/src/services/domain.ts b/packages/server/src/services/domain.ts
index d2e23c06..b99c4869 100644
--- a/packages/server/src/services/domain.ts
+++ b/packages/server/src/services/domain.ts
@@ -4,7 +4,7 @@ import { manageDomain } from "@dokploy/server/utils/traefik/domain";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { type apiCreateDomain, domains } from "../db/schema";
-import { findUserById } from "./admin";
+import { findAdmin, findAdminById } from "./admin";
import { findApplicationById } from "./application";
import { findServerById } from "./server";
@@ -40,7 +40,7 @@ export const createDomain = async (input: typeof apiCreateDomain._type) => {
export const generateTraefikMeDomain = async (
appName: string,
- userId: string,
+ adminId: string,
serverId?: string,
) => {
if (serverId) {
@@ -57,7 +57,7 @@ export const generateTraefikMeDomain = async (
projectName: appName,
});
}
- const admin = await findUserById(userId);
+ const admin = await findAdminById(adminId);
return generateRandomDomain({
serverIp: admin?.serverIp || "",
projectName: appName,
@@ -126,6 +126,7 @@ export const updateDomainById = async (
export const removeDomainById = async (domainId: string) => {
await findDomainById(domainId);
+ // TODO: fix order
const result = await db
.delete(domains)
.where(eq(domains.domainId, domainId))
diff --git a/packages/server/src/services/github.ts b/packages/server/src/services/github.ts
index 19deb2b2..a5d9d863 100644
--- a/packages/server/src/services/github.ts
+++ b/packages/server/src/services/github.ts
@@ -12,14 +12,14 @@ import { updatePreviewDeployment } from "./preview-deployment";
export type Github = typeof github.$inferSelect;
export const createGithub = async (
input: typeof apiCreateGithub._type,
- organizationId: string,
+ adminId: string,
) => {
return await db.transaction(async (tx) => {
const newGitProvider = await tx
.insert(gitProvider)
.values({
providerType: "github",
- organizationId: organizationId,
+ adminId: adminId,
name: input.name,
})
.returning()
@@ -119,7 +119,7 @@ export const issueCommentExists = async ({
comment_id: comment_id,
});
return true;
- } catch (_error) {
+ } catch (error) {
return false;
}
};
diff --git a/packages/server/src/services/gitlab.ts b/packages/server/src/services/gitlab.ts
index fdca2775..8e1362c9 100644
--- a/packages/server/src/services/gitlab.ts
+++ b/packages/server/src/services/gitlab.ts
@@ -1,7 +1,9 @@
import { db } from "@dokploy/server/db";
import {
type apiCreateGitlab,
+ type bitbucket,
gitProvider,
+ type github,
gitlab,
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
@@ -11,14 +13,14 @@ export type Gitlab = typeof gitlab.$inferSelect;
export const createGitlab = async (
input: typeof apiCreateGitlab._type,
- organizationId: string,
+ adminId: string,
) => {
return await db.transaction(async (tx) => {
const newGitProvider = await tx
.insert(gitProvider)
.values({
providerType: "gitlab",
- organizationId: organizationId,
+ adminId: adminId,
name: input.name,
})
.returning()
diff --git a/packages/server/src/services/mariadb.ts b/packages/server/src/services/mariadb.ts
index 00be29d6..8257b587 100644
--- a/packages/server/src/services/mariadb.ts
+++ b/packages/server/src/services/mariadb.ts
@@ -4,7 +4,7 @@ import {
backups,
mariadb,
} from "@dokploy/server/db/schema";
-import { buildAppName } from "@dokploy/server/db/schema";
+import { buildAppName, cleanAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import { buildMariadb } from "@dokploy/server/utils/databases/mariadb";
import { pullImage } from "@dokploy/server/utils/docker/utils";
diff --git a/packages/server/src/services/mongo.ts b/packages/server/src/services/mongo.ts
index 0ac4cc63..031a6013 100644
--- a/packages/server/src/services/mongo.ts
+++ b/packages/server/src/services/mongo.ts
@@ -1,6 +1,6 @@
import { db } from "@dokploy/server/db";
import { type apiCreateMongo, backups, mongo } from "@dokploy/server/db/schema";
-import { buildAppName } from "@dokploy/server/db/schema";
+import { buildAppName, cleanAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import { buildMongo } from "@dokploy/server/utils/databases/mongo";
import { pullImage } from "@dokploy/server/utils/docker/utils";
diff --git a/packages/server/src/services/mount.ts b/packages/server/src/services/mount.ts
index 836feace..dd7bd3e9 100644
--- a/packages/server/src/services/mount.ts
+++ b/packages/server/src/services/mount.ts
@@ -64,7 +64,7 @@ export const createMount = async (input: typeof apiCreateMount._type) => {
console.log(error);
throw new TRPCError({
code: "BAD_REQUEST",
- message: `Error ${error instanceof Error ? error.message : error}`,
+ message: "Error creating the mount",
cause: error,
});
}
@@ -91,7 +91,7 @@ export const createFileMount = async (mountId: string) => {
console.log(`Error creating the file mount: ${error}`);
throw new TRPCError({
code: "BAD_REQUEST",
- message: `Error creating the mount ${error instanceof Error ? error.message : error}`,
+ message: "Error creating the mount",
cause: error,
});
}
@@ -123,8 +123,8 @@ export const updateMount = async (
mountId: string,
mountData: Partial,
) => {
- return await db.transaction(async (tx) => {
- const mount = await tx
+ return await db.transaction(async (transaction) => {
+ const mount = await db
.update(mounts)
.set({
...mountData,
@@ -211,7 +211,7 @@ export const deleteFileMount = async (mountId: string) => {
} else {
await removeFileOrDirectory(fullPath);
}
- } catch (_error) {}
+ } catch (error) {}
};
export const getBaseFilesPath = async (mountId: string) => {
diff --git a/packages/server/src/services/notification.ts b/packages/server/src/services/notification.ts
index 16ba2085..2b62b457 100644
--- a/packages/server/src/services/notification.ts
+++ b/packages/server/src/services/notification.ts
@@ -24,7 +24,7 @@ export type Notification = typeof notifications.$inferSelect;
export const createSlackNotification = async (
input: typeof apiCreateSlack._type,
- organizationId: string,
+ adminId: string,
) => {
await db.transaction(async (tx) => {
const newSlack = await tx
@@ -54,8 +54,7 @@ export const createSlackNotification = async (
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
notificationType: "slack",
- organizationId: organizationId,
- serverThreshold: input.serverThreshold,
+ adminId: adminId,
})
.returning()
.then((value) => value[0]);
@@ -84,8 +83,7 @@ export const updateSlackNotification = async (
databaseBackup: input.databaseBackup,
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
- organizationId: input.organizationId,
- serverThreshold: input.serverThreshold,
+ adminId: input.adminId,
})
.where(eq(notifications.notificationId, input.notificationId))
.returning()
@@ -114,7 +112,7 @@ export const updateSlackNotification = async (
export const createTelegramNotification = async (
input: typeof apiCreateTelegram._type,
- organizationId: string,
+ adminId: string,
) => {
await db.transaction(async (tx) => {
const newTelegram = await tx
@@ -122,7 +120,6 @@ export const createTelegramNotification = async (
.values({
botToken: input.botToken,
chatId: input.chatId,
- messageThreadId: input.messageThreadId,
})
.returning()
.then((value) => value[0]);
@@ -145,8 +142,7 @@ export const createTelegramNotification = async (
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
notificationType: "telegram",
- organizationId: organizationId,
- serverThreshold: input.serverThreshold,
+ adminId: adminId,
})
.returning()
.then((value) => value[0]);
@@ -175,8 +171,7 @@ export const updateTelegramNotification = async (
databaseBackup: input.databaseBackup,
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
- organizationId: input.organizationId,
- serverThreshold: input.serverThreshold,
+ adminId: input.adminId,
})
.where(eq(notifications.notificationId, input.notificationId))
.returning()
@@ -194,7 +189,6 @@ export const updateTelegramNotification = async (
.set({
botToken: input.botToken,
chatId: input.chatId,
- messageThreadId: input.messageThreadId,
})
.where(eq(telegram.telegramId, input.telegramId))
.returning()
@@ -206,7 +200,7 @@ export const updateTelegramNotification = async (
export const createDiscordNotification = async (
input: typeof apiCreateDiscord._type,
- organizationId: string,
+ adminId: string,
) => {
await db.transaction(async (tx) => {
const newDiscord = await tx
@@ -236,8 +230,7 @@ export const createDiscordNotification = async (
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
notificationType: "discord",
- organizationId: organizationId,
- serverThreshold: input.serverThreshold,
+ adminId: adminId,
})
.returning()
.then((value) => value[0]);
@@ -266,8 +259,7 @@ export const updateDiscordNotification = async (
databaseBackup: input.databaseBackup,
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
- organizationId: input.organizationId,
- serverThreshold: input.serverThreshold,
+ adminId: input.adminId,
})
.where(eq(notifications.notificationId, input.notificationId))
.returning()
@@ -296,7 +288,7 @@ export const updateDiscordNotification = async (
export const createEmailNotification = async (
input: typeof apiCreateEmail._type,
- organizationId: string,
+ adminId: string,
) => {
await db.transaction(async (tx) => {
const newEmail = await tx
@@ -330,8 +322,7 @@ export const createEmailNotification = async (
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
notificationType: "email",
- organizationId: organizationId,
- serverThreshold: input.serverThreshold,
+ adminId: adminId,
})
.returning()
.then((value) => value[0]);
@@ -360,8 +351,7 @@ export const updateEmailNotification = async (
databaseBackup: input.databaseBackup,
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
- organizationId: input.organizationId,
- serverThreshold: input.serverThreshold,
+ adminId: input.adminId,
})
.where(eq(notifications.notificationId, input.notificationId))
.returning()
@@ -394,7 +384,7 @@ export const updateEmailNotification = async (
export const createGotifyNotification = async (
input: typeof apiCreateGotify._type,
- organizationId: string,
+ adminId: string,
) => {
await db.transaction(async (tx) => {
const newGotify = await tx
@@ -426,7 +416,7 @@ export const createGotifyNotification = async (
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
notificationType: "gotify",
- organizationId: organizationId,
+ adminId: adminId,
})
.returning()
.then((value) => value[0]);
@@ -455,7 +445,7 @@ export const updateGotifyNotification = async (
databaseBackup: input.databaseBackup,
dokployRestart: input.dokployRestart,
dockerCleanup: input.dockerCleanup,
- organizationId: input.organizationId,
+ adminId: input.adminId,
})
.where(eq(notifications.notificationId, input.notificationId))
.returning()
diff --git a/packages/server/src/services/postgres.ts b/packages/server/src/services/postgres.ts
index 75b81c50..682d3f78 100644
--- a/packages/server/src/services/postgres.ts
+++ b/packages/server/src/services/postgres.ts
@@ -4,7 +4,7 @@ import {
backups,
postgres,
} from "@dokploy/server/db/schema";
-import { buildAppName } from "@dokploy/server/db/schema";
+import { buildAppName, cleanAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import { buildPostgres } from "@dokploy/server/utils/databases/postgres";
import { pullImage } from "@dokploy/server/utils/docker/utils";
diff --git a/packages/server/src/services/preview-deployment.ts b/packages/server/src/services/preview-deployment.ts
index a1ffca4b..ab38c17c 100644
--- a/packages/server/src/services/preview-deployment.ts
+++ b/packages/server/src/services/preview-deployment.ts
@@ -2,20 +2,23 @@ import { db } from "@dokploy/server/db";
import {
type apiCreatePreviewDeployment,
deployments,
- organization,
previewDeployments,
} from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
import { and, desc, eq } from "drizzle-orm";
-import { generatePassword } from "../templates/utils";
+import { slugify } from "../setup/server-setup";
+import { generatePassword, generateRandomDomain } from "../templates/utils";
import { removeService } from "../utils/docker/utils";
import { removeDirectoryCode } from "../utils/filesystem/directory";
import { authGithub } from "../utils/providers/github";
import { removeTraefikConfig } from "../utils/traefik/application";
import { manageDomain } from "../utils/traefik/domain";
-import { findUserById } from "./admin";
+import { findAdminById } from "./admin";
import { findApplicationById } from "./application";
-import { removeDeploymentsByPreviewDeploymentId } from "./deployment";
+import {
+ removeDeployments,
+ removeDeploymentsByPreviewDeploymentId,
+} from "./deployment";
import { createDomain } from "./domain";
import { type Github, getIssueComment } from "./github";
@@ -103,17 +106,13 @@ export const removePreviewDeployment = async (previewDeploymentId: string) => {
for (const operation of cleanupOperations) {
try {
await operation();
- } catch (_error) {}
+ } catch (error) {}
}
return deployment[0];
} catch (error) {
- const message =
- error instanceof Error
- ? error.message
- : "Error deleting this preview deployment";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error deleting this preview deployment",
});
}
};
@@ -155,14 +154,11 @@ export const createPreviewDeployment = async (
const application = await findApplicationById(schema.applicationId);
const appName = `preview-${application.appName}-${generatePassword(6)}`;
- const org = await db.query.organization.findFirst({
- where: eq(organization.id, application.project.organizationId),
- });
const generateDomain = await generateWildcardDomain(
application.previewWildcard || "*.traefik.me",
appName,
application.server?.ipAddress || "",
- org?.ownerId || "",
+ application.project.adminId,
);
const octokit = authGithub(application?.github as Github);
@@ -254,7 +250,7 @@ const generateWildcardDomain = async (
baseDomain: string,
appName: string,
serverIp: string,
- userId: string,
+ adminId: string,
): Promise => {
if (!baseDomain.startsWith("*.")) {
throw new Error('The base domain must start with "*."');
@@ -272,7 +268,7 @@ const generateWildcardDomain = async (
}
if (!ip) {
- const admin = await findUserById(userId);
+ const admin = await findAdminById(adminId);
ip = admin?.serverIp || "";
}
diff --git a/packages/server/src/services/project.ts b/packages/server/src/services/project.ts
index b740834b..adaa07ea 100644
--- a/packages/server/src/services/project.ts
+++ b/packages/server/src/services/project.ts
@@ -16,13 +16,13 @@ export type Project = typeof projects.$inferSelect;
export const createProject = async (
input: typeof apiCreateProject._type,
- organizationId: string,
+ adminId: string,
) => {
const newProject = await db
.insert(projects)
.values({
...input,
- organizationId: organizationId,
+ adminId: adminId,
})
.returning()
.then((value) => value[0]);
diff --git a/packages/server/src/services/redirect.ts b/packages/server/src/services/redirect.ts
index 1896105f..f16dbe42 100644
--- a/packages/server/src/services/redirect.ts
+++ b/packages/server/src/services/redirect.ts
@@ -6,7 +6,7 @@ import {
updateRedirectMiddleware,
} from "@dokploy/server/utils/traefik/redirect";
import { TRPCError } from "@trpc/server";
-import { eq } from "drizzle-orm";
+import { desc, eq } from "drizzle-orm";
import type { z } from "zod";
import { findApplicationById } from "./application";
export type Redirect = typeof redirects.$inferSelect;
@@ -114,11 +114,9 @@ export const updateRedirectById = async (
return redirect;
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error updating this redirect";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error updating this redirect",
});
}
};
diff --git a/packages/server/src/services/redis.ts b/packages/server/src/services/redis.ts
index 9f4a1f9e..e0dbbe02 100644
--- a/packages/server/src/services/redis.ts
+++ b/packages/server/src/services/redis.ts
@@ -1,6 +1,6 @@
import { db } from "@dokploy/server/db";
import { type apiCreateRedis, redis } from "@dokploy/server/db/schema";
-import { buildAppName } from "@dokploy/server/db/schema";
+import { buildAppName, cleanAppName } from "@dokploy/server/db/schema";
import { generatePassword } from "@dokploy/server/templates/utils";
import { buildRedis } from "@dokploy/server/utils/databases/redis";
import { pullImage } from "@dokploy/server/utils/docker/utils";
diff --git a/packages/server/src/services/registry.ts b/packages/server/src/services/registry.ts
index 6468cd97..2bcf3a4a 100644
--- a/packages/server/src/services/registry.ts
+++ b/packages/server/src/services/registry.ts
@@ -12,14 +12,14 @@ export type Registry = typeof registry.$inferSelect;
export const createRegistry = async (
input: typeof apiCreateRegistry._type,
- organizationId: string,
+ adminId: string,
) => {
return await db.transaction(async (tx) => {
const newRegistry = await tx
.insert(registry)
.values({
...input,
- organizationId: organizationId,
+ adminId: adminId,
})
.returning()
.then((value) => value[0]);
@@ -112,11 +112,9 @@ export const updateRegistry = async (
return response;
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error updating this registry";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error updating this registry",
});
}
};
@@ -137,11 +135,9 @@ export const findRegistryById = async (registryId: string) => {
return registryResponse;
};
-export const findAllRegistryByOrganizationId = async (
- organizationId: string,
-) => {
+export const findAllRegistryByAdminId = async (adminId: string) => {
const registryResponse = await db.query.registry.findMany({
- where: eq(registry.organizationId, organizationId),
+ where: eq(registry.adminId, adminId),
});
return registryResponse;
};
diff --git a/packages/server/src/services/security.ts b/packages/server/src/services/security.ts
index d6947b88..5efca19f 100644
--- a/packages/server/src/services/security.ts
+++ b/packages/server/src/services/security.ts
@@ -76,11 +76,9 @@ export const deleteSecurityById = async (securityId: string) => {
await removeSecurityMiddleware(application, result);
return result;
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error removing this security";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error removing this security",
});
}
};
@@ -100,11 +98,9 @@ export const updateSecurityById = async (
return response[0];
} catch (error) {
- const message =
- error instanceof Error ? error.message : "Error updating this security";
throw new TRPCError({
code: "BAD_REQUEST",
- message,
+ message: "Error updating this security",
});
}
};
diff --git a/packages/server/src/services/server.ts b/packages/server/src/services/server.ts
index a4d5c5d8..081b19fa 100644
--- a/packages/server/src/services/server.ts
+++ b/packages/server/src/services/server.ts
@@ -1,24 +1,19 @@
import { db } from "@dokploy/server/db";
-import {
- type apiCreateServer,
- organization,
- server,
-} from "@dokploy/server/db/schema";
+import { type apiCreateServer, server } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
-import { eq } from "drizzle-orm";
+import { desc, eq } from "drizzle-orm";
export type Server = typeof server.$inferSelect;
export const createServer = async (
input: typeof apiCreateServer._type,
- organizationId: string,
+ adminId: string,
) => {
const newServer = await db
.insert(server)
.values({
...input,
- organizationId: organizationId,
- createdAt: new Date().toISOString(),
+ adminId: adminId,
})
.returning()
.then((value) => value[0]);
@@ -50,16 +45,12 @@ export const findServerById = async (serverId: string) => {
return currentServer;
};
-export const findServersByUserId = async (userId: string) => {
- const orgs = await db.query.organization.findMany({
- where: eq(organization.ownerId, userId),
- with: {
- servers: true,
- },
+export const findServersByAdminId = async (adminId: string) => {
+ const servers = await db.query.server.findMany({
+ where: eq(server.adminId, adminId),
+ orderBy: desc(server.createdAt),
});
- const servers = orgs.flatMap((org) => org.servers);
-
return servers;
};
diff --git a/packages/server/src/services/settings.ts b/packages/server/src/services/settings.ts
index 75613be0..37f7b2ee 100644
--- a/packages/server/src/services/settings.ts
+++ b/packages/server/src/services/settings.ts
@@ -5,6 +5,7 @@ import {
execAsync,
execAsyncRemote,
} from "@dokploy/server/utils/process/execAsync";
+// import packageInfo from "../../../package.json";
export interface IUpdateData {
latestVersion: string | null;
@@ -169,6 +170,7 @@ echo "$json_output"
const result = JSON.parse(stdout);
return result;
}
+ const items = readdirSync(dirPath, { withFileTypes: true });
const stack = [dirPath];
const result: TreeDataItem[] = [];
@@ -211,35 +213,3 @@ echo "$json_output"
}
return result;
};
-
-export const cleanupFullDocker = async (serverId?: string | null) => {
- const cleanupImages = "docker image prune --force";
- const cleanupVolumes = "docker volume prune --force";
- const cleanupContainers = "docker container prune --force";
- const cleanupSystem = "docker system prune --force --volumes";
- const cleanupBuilder = "docker builder prune --force";
-
- try {
- if (serverId) {
- await execAsyncRemote(
- serverId,
- `
- ${cleanupImages}
- ${cleanupVolumes}
- ${cleanupContainers}
- ${cleanupSystem}
- ${cleanupBuilder}
- `,
- );
- }
- await execAsync(`
- ${cleanupImages}
- ${cleanupVolumes}
- ${cleanupContainers}
- ${cleanupSystem}
- ${cleanupBuilder}
- `);
- } catch (error) {
- console.log(error);
- }
-};
diff --git a/packages/server/src/services/user.ts b/packages/server/src/services/user.ts
index 39ac95ce..d8d9862c 100644
--- a/packages/server/src/services/user.ts
+++ b/packages/server/src/services/user.ts
@@ -1,53 +1,80 @@
import { db } from "@dokploy/server/db";
-import { apikey, member, users_temp } from "@dokploy/server/db/schema";
+import { users } from "@dokploy/server/db/schema";
import { TRPCError } from "@trpc/server";
-import { and, eq } from "drizzle-orm";
-import { auth } from "../lib/auth";
+import { eq } from "drizzle-orm";
-export type User = typeof users_temp.$inferSelect;
+export type User = typeof users.$inferSelect;
-export const addNewProject = async (
- userId: string,
- projectId: string,
- organizationId: string,
-) => {
- const userR = await findMemberById(userId, organizationId);
-
- await db
- .update(member)
- .set({
- accessedProjects: [...userR.accessedProjects, projectId],
- })
- .where(
- and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
- );
+export const findUserById = async (userId: string) => {
+ const user = await db.query.users.findFirst({
+ where: eq(users.userId, userId),
+ });
+ if (!user) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "User not found",
+ });
+ }
+ return user;
};
-export const addNewService = async (
- userId: string,
- serviceId: string,
- organizationId: string,
-) => {
- const userR = await findMemberById(userId, organizationId);
+export const findUserByAuthId = async (authId: string) => {
+ const user = await db.query.users.findFirst({
+ where: eq(users.authId, authId),
+ with: {
+ auth: true,
+ },
+ });
+ if (!user) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "User not found",
+ });
+ }
+ return user;
+};
+
+export const findUsers = async (adminId: string) => {
+ const currentUsers = await db.query.users.findMany({
+ where: eq(users.adminId, adminId),
+ with: {
+ auth: {
+ columns: {
+ secret: false,
+ },
+ },
+ },
+ });
+ return currentUsers;
+};
+
+export const addNewProject = async (authId: string, projectId: string) => {
+ const user = await findUserByAuthId(authId);
+
await db
- .update(member)
+ .update(users)
.set({
- accessedServices: [...userR.accessedServices, serviceId],
+ accessedProjects: [...user.accessedProjects, projectId],
})
- .where(
- and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
- );
+ .where(eq(users.authId, authId));
+};
+
+export const addNewService = async (authId: string, serviceId: string) => {
+ const user = await findUserByAuthId(authId);
+ await db
+ .update(users)
+ .set({
+ accessedServices: [...user.accessedServices, serviceId],
+ })
+ .where(eq(users.authId, authId));
};
export const canPerformCreationService = async (
userId: string,
projectId: string,
- organizationId: string,
) => {
- const { accessedProjects, canCreateServices } = await findMemberById(
- userId,
- organizationId,
- );
+ const { accessedProjects, canCreateServices } =
+ await findUserByAuthId(userId);
const haveAccessToProject = accessedProjects.includes(projectId);
if (canCreateServices && haveAccessToProject) {
@@ -60,9 +87,8 @@ export const canPerformCreationService = async (
export const canPerformAccessService = async (
userId: string,
serviceId: string,
- organizationId: string,
) => {
- const { accessedServices } = await findMemberById(userId, organizationId);
+ const { accessedServices } = await findUserByAuthId(userId);
const haveAccessToService = accessedServices.includes(serviceId);
if (haveAccessToService) {
@@ -73,14 +99,11 @@ export const canPerformAccessService = async (
};
export const canPeformDeleteService = async (
- userId: string,
+ authId: string,
serviceId: string,
- organizationId: string,
) => {
- const { accessedServices, canDeleteServices } = await findMemberById(
- userId,
- organizationId,
- );
+ const { accessedServices, canDeleteServices } =
+ await findUserByAuthId(authId);
const haveAccessToService = accessedServices.includes(serviceId);
if (canDeleteServices && haveAccessToService) {
@@ -90,11 +113,8 @@ export const canPeformDeleteService = async (
return false;
};
-export const canPerformCreationProject = async (
- userId: string,
- organizationId: string,
-) => {
- const { canCreateProjects } = await findMemberById(userId, organizationId);
+export const canPerformCreationProject = async (authId: string) => {
+ const { canCreateProjects } = await findUserByAuthId(authId);
if (canCreateProjects) {
return true;
@@ -103,11 +123,8 @@ export const canPerformCreationProject = async (
return false;
};
-export const canPerformDeleteProject = async (
- userId: string,
- organizationId: string,
-) => {
- const { canDeleteProjects } = await findMemberById(userId, organizationId);
+export const canPerformDeleteProject = async (authId: string) => {
+ const { canDeleteProjects } = await findUserByAuthId(authId);
if (canDeleteProjects) {
return true;
@@ -117,11 +134,10 @@ export const canPerformDeleteProject = async (
};
export const canPerformAccessProject = async (
- userId: string,
+ authId: string,
projectId: string,
- organizationId: string,
) => {
- const { accessedProjects } = await findMemberById(userId, organizationId);
+ const { accessedProjects } = await findUserByAuthId(authId);
const haveAccessToProject = accessedProjects.includes(projectId);
@@ -131,45 +147,26 @@ export const canPerformAccessProject = async (
return false;
};
-export const canAccessToTraefikFiles = async (
- userId: string,
- organizationId: string,
-) => {
- const { canAccessToTraefikFiles } = await findMemberById(
- userId,
- organizationId,
- );
+export const canAccessToTraefikFiles = async (authId: string) => {
+ const { canAccessToTraefikFiles } = await findUserByAuthId(authId);
return canAccessToTraefikFiles;
};
export const checkServiceAccess = async (
- userId: string,
+ authId: string,
serviceId: string,
- organizationId: string,
action = "access" as "access" | "create" | "delete",
) => {
let hasPermission = false;
switch (action) {
case "create":
- hasPermission = await canPerformCreationService(
- userId,
- serviceId,
- organizationId,
- );
+ hasPermission = await canPerformCreationService(authId, serviceId);
break;
case "access":
- hasPermission = await canPerformAccessService(
- userId,
- serviceId,
- organizationId,
- );
+ hasPermission = await canPerformAccessService(authId, serviceId);
break;
case "delete":
- hasPermission = await canPeformDeleteService(
- userId,
- serviceId,
- organizationId,
- );
+ hasPermission = await canPeformDeleteService(authId, serviceId);
break;
default:
hasPermission = false;
@@ -185,7 +182,6 @@ export const checkServiceAccess = async (
export const checkProjectAccess = async (
authId: string,
action: "create" | "delete" | "access",
- organizationId: string,
projectId?: string,
) => {
let hasPermission = false;
@@ -194,14 +190,13 @@ export const checkProjectAccess = async (
hasPermission = await canPerformAccessProject(
authId,
projectId as string,
- organizationId,
);
break;
case "create":
- hasPermission = await canPerformCreationProject(authId, organizationId);
+ hasPermission = await canPerformCreationProject(authId);
break;
case "delete":
- hasPermission = await canPerformDeleteProject(authId, organizationId);
+ hasPermission = await canPerformDeleteProject(authId);
break;
default:
hasPermission = false;
@@ -213,82 +208,3 @@ export const checkProjectAccess = async (
});
}
};
-
-export const findMemberById = async (
- userId: string,
- organizationId: string,
-) => {
- const result = await db.query.member.findFirst({
- where: and(
- eq(member.userId, userId),
- eq(member.organizationId, organizationId),
- ),
- with: {
- user: true,
- },
- });
-
- if (!result) {
- throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "Permission denied",
- });
- }
- return result;
-};
-
-export const updateUser = async (userId: string, userData: Partial) => {
- const user = await db
- .update(users_temp)
- .set({
- ...userData,
- })
- .where(eq(users_temp.id, userId))
- .returning()
- .then((res) => res[0]);
-
- return user;
-};
-
-export const createApiKey = async (
- userId: string,
- input: {
- name: string;
- prefix?: string;
- expiresIn?: number;
- metadata: {
- organizationId: string;
- };
- rateLimitEnabled?: boolean;
- rateLimitTimeWindow?: number;
- rateLimitMax?: number;
- remaining?: number;
- refillAmount?: number;
- refillInterval?: number;
- },
-) => {
- const apiKey = await auth.createApiKey({
- body: {
- name: input.name,
- expiresIn: input.expiresIn,
- prefix: input.prefix,
- rateLimitEnabled: input.rateLimitEnabled,
- rateLimitTimeWindow: input.rateLimitTimeWindow,
- rateLimitMax: input.rateLimitMax,
- remaining: input.remaining,
- refillAmount: input.refillAmount,
- refillInterval: input.refillInterval,
- userId,
- },
- });
-
- if (input.metadata) {
- await db
- .update(apikey)
- .set({
- metadata: JSON.stringify(input.metadata),
- })
- .where(eq(apikey.id, apiKey.id));
- }
- return apiKey;
-};
diff --git a/packages/server/src/setup/monitoring-setup.ts b/packages/server/src/setup/monitoring-setup.ts
deleted file mode 100644
index 75b9a928..00000000
--- a/packages/server/src/setup/monitoring-setup.ts
+++ /dev/null
@@ -1,148 +0,0 @@
-import { findServerById } from "@dokploy/server/services/server";
-import type { ContainerCreateOptions } from "dockerode";
-import { IS_CLOUD } from "../constants";
-import { findUserById } from "../services/admin";
-import { getDokployImageTag } from "../services/settings";
-import { pullImage, pullRemoteImage } from "../utils/docker/utils";
-import { execAsync, execAsyncRemote } from "../utils/process/execAsync";
-import { getRemoteDocker } from "../utils/servers/remote-docker";
-
-export const setupMonitoring = async (serverId: string) => {
- const server = await findServerById(serverId);
-
- const containerName = "dokploy-monitoring";
- let imageName = "dokploy/monitoring:latest";
-
- if (
- (getDokployImageTag() !== "latest" ||
- process.env.NODE_ENV === "development") &&
- !IS_CLOUD
- ) {
- imageName = "dokploy/monitoring:canary";
- }
-
- const settings: ContainerCreateOptions = {
- name: containerName,
- Env: [`METRICS_CONFIG=${JSON.stringify(server?.metricsConfig)}`],
- Image: imageName,
- HostConfig: {
- // Memory: 100 * 1024 * 1024, // 100MB en bytes
- // PidMode: "host",
- // CapAdd: ["NET_ADMIN", "SYS_ADMIN"],
- // Privileged: true,
- PortBindings: {
- [`${server.metricsConfig.server.port}/tcp`]: [
- {
- HostPort: server.metricsConfig.server.port.toString(),
- },
- ],
- },
- Binds: [
- "/var/run/docker.sock:/var/run/docker.sock:ro",
- "/sys:/host/sys:ro",
- "/etc/os-release:/etc/os-release:ro",
- "/proc:/host/proc:ro",
- "/etc/dokploy/monitoring/monitoring.db:/app/monitoring.db",
- ],
- NetworkMode: "host",
- },
- ExposedPorts: {
- [`${server.metricsConfig.server.port}/tcp`]: {},
- },
- };
- const docker = await getRemoteDocker(serverId);
- try {
- await execAsyncRemote(
- serverId,
- "mkdir -p /etc/dokploy/monitoring && touch /etc/dokploy/monitoring/monitoring.db",
- );
- if (serverId) {
- await pullRemoteImage(imageName, serverId);
- }
-
- // Check if container exists
- const container = docker.getContainer(containerName);
- try {
- await container.inspect();
- await container.remove({ force: true });
- console.log("Removed existing container");
- } catch (_error) {
- // Container doesn't exist, continue
- }
-
- await docker.createContainer(settings);
- const newContainer = docker.getContainer(containerName);
- await newContainer.start();
-
- console.log("Monitoring Started ");
- } catch (error) {
- console.log("Monitoring Not Found: Starting ", error);
- }
-};
-
-export const setupWebMonitoring = async (userId: string) => {
- const user = await findUserById(userId);
-
- const containerName = "dokploy-monitoring";
- let imageName = "dokploy/monitoring:latest";
-
- if (
- (getDokployImageTag() !== "latest" ||
- process.env.NODE_ENV === "development") &&
- !IS_CLOUD
- ) {
- imageName = "dokploy/monitoring:canary";
- }
-
- const settings: ContainerCreateOptions = {
- name: containerName,
- Env: [`METRICS_CONFIG=${JSON.stringify(user?.metricsConfig)}`],
- Image: imageName,
- HostConfig: {
- // Memory: 100 * 1024 * 1024, // 100MB en bytes
- // PidMode: "host",
- // CapAdd: ["NET_ADMIN", "SYS_ADMIN"],
- // Privileged: true,
- PortBindings: {
- [`${user?.metricsConfig?.server?.port}/tcp`]: [
- {
- HostPort: user?.metricsConfig?.server?.port.toString(),
- },
- ],
- },
- Binds: [
- "/var/run/docker.sock:/var/run/docker.sock:ro",
- "/sys:/host/sys:ro",
- "/etc/os-release:/etc/os-release:ro",
- "/proc:/host/proc:ro",
- "/etc/dokploy/monitoring/monitoring.db:/app/monitoring.db",
- ],
- // NetworkMode: "host",
- },
- ExposedPorts: {
- [`${user?.metricsConfig?.server?.port}/tcp`]: {},
- },
- };
- const docker = await getRemoteDocker();
- try {
- await execAsync(
- "mkdir -p /etc/dokploy/monitoring && touch /etc/dokploy/monitoring/monitoring.db",
- );
- await pullImage(imageName);
-
- const container = docker.getContainer(containerName);
- try {
- await container.inspect();
- await container.remove({ force: true });
- console.log("Removed existing container");
- } catch (_error) {}
-
- await docker.createContainer(settings);
- const newContainer = docker.getContainer(containerName);
- await newContainer.start();
-
- console.log("Monitoring Started ");
- } catch (error) {
- console.log("Monitoring Not Found: Starting ", error);
- }
-};
diff --git a/packages/server/src/setup/postgres-setup.ts b/packages/server/src/setup/postgres-setup.ts
index cf162f1e..b5794c2b 100644
--- a/packages/server/src/setup/postgres-setup.ts
+++ b/packages/server/src/setup/postgres-setup.ts
@@ -54,16 +54,10 @@ export const initializePostgres = async () => {
version: Number.parseInt(inspect.Version.Index),
...settings,
});
+
console.log("Postgres Started ✅");
- } catch (_) {
- try {
- await docker.createService(settings);
- } catch (error: any) {
- if (error?.statusCode !== 409) {
- throw error;
- }
- console.log("Postgres service already exists, continuing...");
- }
+ } catch (error) {
+ await docker.createService(settings);
console.log("Postgres Not Found: Starting ✅");
}
};
diff --git a/packages/server/src/setup/redis-setup.ts b/packages/server/src/setup/redis-setup.ts
index 7366546d..1c3b545a 100644
--- a/packages/server/src/setup/redis-setup.ts
+++ b/packages/server/src/setup/redis-setup.ts
@@ -52,15 +52,8 @@ export const initializeRedis = async () => {
...settings,
});
console.log("Redis Started ✅");
- } catch (_) {
- try {
- await docker.createService(settings);
- } catch (error: any) {
- if (error?.statusCode !== 409) {
- throw error;
- }
- console.log("Redis service already exists, continuing...");
- }
+ } catch (error) {
+ await docker.createService(settings);
console.log("Redis Not Found: Starting ✅");
}
};
diff --git a/packages/server/src/setup/server-audit.ts b/packages/server/src/setup/server-audit.ts
index b9283c31..df00e9a7 100644
--- a/packages/server/src/setup/server-audit.ts
+++ b/packages/server/src/setup/server-audit.ts
@@ -89,7 +89,7 @@ export const serverAudit = async (serverId: string) => {
.on("data", (data: string) => {
output += data;
})
- .stderr.on("data", (_data) => {});
+ .stderr.on("data", (data) => {});
});
})
.on("error", (err) => {
diff --git a/packages/server/src/setup/server-validate.ts b/packages/server/src/setup/server-validate.ts
index c86206b6..4ca21df8 100644
--- a/packages/server/src/setup/server-validate.ts
+++ b/packages/server/src/setup/server-validate.ts
@@ -128,7 +128,7 @@ export const serverValidate = async (serverId: string) => {
.on("data", (data: string) => {
output += data;
})
- .stderr.on("data", (_data) => {});
+ .stderr.on("data", (data) => {});
});
})
.on("error", (err) => {
diff --git a/packages/server/src/setup/setup.ts b/packages/server/src/setup/setup.ts
index eeef32dd..c5987702 100644
--- a/packages/server/src/setup/setup.ts
+++ b/packages/server/src/setup/setup.ts
@@ -18,7 +18,7 @@ export const dockerSwarmInitialized = async () => {
await docker.swarmInspect();
return true;
- } catch (_e) {
+ } catch (e) {
return false;
}
};
@@ -41,7 +41,7 @@ export const dockerNetworkInitialized = async () => {
try {
await docker.getNetwork("dokploy-network").inspect();
return true;
- } catch (_e) {
+ } catch (e) {
return false;
}
};
diff --git a/packages/server/src/setup/traefik-setup.ts b/packages/server/src/setup/traefik-setup.ts
index e8d01942..270a4447 100644
--- a/packages/server/src/setup/traefik-setup.ts
+++ b/packages/server/src/setup/traefik-setup.ts
@@ -68,6 +68,9 @@ export const initializeTraefik = async ({
Replicas: 1,
},
},
+ Labels: {
+ "traefik.enable": "true",
+ },
EndpointSpec: {
Ports: [
{
@@ -127,15 +130,8 @@ export const initializeTraefik = async ({
});
console.log("Traefik Started ✅");
- } catch (_) {
- try {
- await docker.createService(settings);
- } catch (error: any) {
- if (error?.statusCode !== 409) {
- throw error;
- }
- console.log("Traefik service already exists, continuing...");
- }
+ } catch (error) {
+ await docker.createService(settings);
console.log("Traefik Not Found: Starting ✅");
}
};
@@ -193,12 +189,10 @@ export const getDefaultTraefikConfig = () => {
: {
swarm: {
exposedByDefault: false,
- watch: true,
+ watch: false,
},
docker: {
exposedByDefault: false,
- watch: true,
- network: "dokploy-network",
},
}),
file: {
@@ -249,12 +243,10 @@ export const getDefaultServerTraefikConfig = () => {
providers: {
swarm: {
exposedByDefault: false,
- watch: true,
+ watch: false,
},
docker: {
exposedByDefault: false,
- watch: true,
- network: "dokploy-network",
},
file: {
directory: "/etc/dokploy/traefik/dynamic",
diff --git a/packages/server/src/types/with.ts b/packages/server/src/types/with.ts
index 467020a2..c4826f73 100644
--- a/packages/server/src/types/with.ts
+++ b/packages/server/src/types/with.ts
@@ -36,7 +36,7 @@ type AnyObj = Record;
type ZodObj = {
[key in keyof T]: z.ZodType;
};
-const _zObject = (arg: ZodObj) => z.object(arg);
+const zObject = (arg: ZodObj) => z.object(arg);
// const goodDogScheme = zObject({
// // prueba: schema.selectDatabaseSchema,
diff --git a/packages/server/src/utils/access-log/handler.ts b/packages/server/src/utils/access-log/handler.ts
index 69d0cc68..b1fd925c 100644
--- a/packages/server/src/utils/access-log/handler.ts
+++ b/packages/server/src/utils/access-log/handler.ts
@@ -1,8 +1,8 @@
import { IS_CLOUD, paths } from "@dokploy/server/constants";
+import { updateAdmin } from "@dokploy/server/services/admin";
import { type RotatingFileStream, createStream } from "rotating-file-stream";
+import { db } from "../../db";
import { execAsync } from "../process/execAsync";
-import { findAdmin } from "@dokploy/server/services/admin";
-import { updateUser } from "@dokploy/server/services/user";
class LogRotationManager {
private static instance: LogRotationManager;
@@ -30,16 +30,17 @@ class LogRotationManager {
}
private async getStateFromDB(): Promise {
- const admin = await findAdmin();
- return admin?.user.enableLogRotation ?? false;
+ const setting = await db.query.admins.findFirst({});
+ return setting?.enableLogRotation ?? false;
}
private async setStateInDB(active: boolean): Promise {
- const admin = await findAdmin();
+ const admin = await db.query.admins.findFirst({});
+
if (!admin) {
return;
}
- await updateUser(admin.user.id, {
+ await updateAdmin(admin?.authId, {
enableLogRotation: active,
});
}
diff --git a/packages/server/src/utils/backups/index.ts b/packages/server/src/utils/backups/index.ts
index 7699a42e..922232a0 100644
--- a/packages/server/src/utils/backups/index.ts
+++ b/packages/server/src/utils/backups/index.ts
@@ -1,3 +1,4 @@
+import { findAdmin } from "@dokploy/server/services/admin";
import { getAllServers } from "@dokploy/server/services/server";
import { scheduleJob } from "node-schedule";
import { db } from "../../db/index";
@@ -11,14 +12,13 @@ import { runMariadbBackup } from "./mariadb";
import { runMongoBackup } from "./mongo";
import { runMySqlBackup } from "./mysql";
import { runPostgresBackup } from "./postgres";
-import { findAdmin } from "../../services/admin";
export const initCronJobs = async () => {
console.log("Setting up cron jobs....");
const admin = await findAdmin();
- if (admin?.user.enableDockerCleanup) {
+ if (admin?.enableDockerCleanup) {
scheduleJob("docker-cleanup", "0 0 * * *", async () => {
console.log(
`Docker Cleanup ${new Date().toLocaleString()}] Running docker cleanup`,
@@ -26,7 +26,7 @@ export const initCronJobs = async () => {
await cleanUpUnusedImages();
await cleanUpDockerBuilder();
await cleanUpSystemPrune();
- await sendDockerCleanupNotifications(admin.user.id);
+ await sendDockerCleanupNotifications(admin.adminId);
});
}
@@ -43,7 +43,7 @@ export const initCronJobs = async () => {
await cleanUpDockerBuilder(serverId);
await cleanUpSystemPrune(serverId);
await sendDockerCleanupNotifications(
- admin.user.id,
+ admin.adminId,
`Docker cleanup for Server ${name} (${serverId})`,
);
});
diff --git a/packages/server/src/utils/backups/mariadb.ts b/packages/server/src/utils/backups/mariadb.ts
index 56c2919c..79cba9c5 100644
--- a/packages/server/src/utils/backups/mariadb.ts
+++ b/packages/server/src/utils/backups/mariadb.ts
@@ -49,7 +49,7 @@ export const runMariadbBackup = async (
projectName: project.name,
databaseType: "mariadb",
type: "success",
- organizationId: project.organizationId,
+ adminId: project.adminId,
});
} catch (error) {
console.log(error);
@@ -60,7 +60,7 @@ export const runMariadbBackup = async (
type: "error",
// @ts-ignore
errorMessage: error?.message || "Error message not provided",
- organizationId: project.organizationId,
+ adminId: project.adminId,
});
throw error;
}
diff --git a/packages/server/src/utils/backups/mongo.ts b/packages/server/src/utils/backups/mongo.ts
index a40ec4f4..ddd1b889 100644
--- a/packages/server/src/utils/backups/mongo.ts
+++ b/packages/server/src/utils/backups/mongo.ts
@@ -46,7 +46,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
projectName: project.name,
databaseType: "mongodb",
type: "success",
- organizationId: project.organizationId,
+ adminId: project.adminId,
});
} catch (error) {
console.log(error);
@@ -57,7 +57,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => {
type: "error",
// @ts-ignore
errorMessage: error?.message || "Error message not provided",
- organizationId: project.organizationId,
+ adminId: project.adminId,
});
throw error;
}
diff --git a/packages/server/src/utils/backups/mysql.ts b/packages/server/src/utils/backups/mysql.ts
index 1272fc3e..b505204c 100644
--- a/packages/server/src/utils/backups/mysql.ts
+++ b/packages/server/src/utils/backups/mysql.ts
@@ -1,3 +1,4 @@
+import { unlink } from "node:fs/promises";
import path from "node:path";
import type { BackupSchedule } from "@dokploy/server/services/backup";
import type { MySql } from "@dokploy/server/services/mysql";
@@ -45,7 +46,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => {
projectName: project.name,
databaseType: "mysql",
type: "success",
- organizationId: project.organizationId,
+ adminId: project.adminId,
});
} catch (error) {
console.log(error);
@@ -56,7 +57,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => {
type: "error",
// @ts-ignore
errorMessage: error?.message || "Error message not provided",
- organizationId: project.organizationId,
+ adminId: project.adminId,
});
throw error;
}
diff --git a/packages/server/src/utils/backups/postgres.ts b/packages/server/src/utils/backups/postgres.ts
index 5ada2aa9..e9609fc8 100644
--- a/packages/server/src/utils/backups/postgres.ts
+++ b/packages/server/src/utils/backups/postgres.ts
@@ -49,7 +49,7 @@ export const runPostgresBackup = async (
projectName: project.name,
databaseType: "postgres",
type: "success",
- organizationId: project.organizationId,
+ adminId: project.adminId,
});
} catch (error) {
await sendDatabaseBackupNotifications({
@@ -59,7 +59,7 @@ export const runPostgresBackup = async (
type: "error",
// @ts-ignore
errorMessage: error?.message || "Error message not provided",
- organizationId: project.organizationId,
+ adminId: project.adminId,
});
throw error;
diff --git a/packages/server/src/utils/backups/utils.ts b/packages/server/src/utils/backups/utils.ts
index c76f7962..0d78ff96 100644
--- a/packages/server/src/utils/backups/utils.ts
+++ b/packages/server/src/utils/backups/utils.ts
@@ -28,7 +28,7 @@ export const removeScheduleBackup = (backupId: string) => {
};
export const getS3Credentials = (destination: Destination) => {
- const { accessKey, secretAccessKey, region, endpoint, provider } =
+ const { accessKey, secretAccessKey, bucket, region, endpoint, provider } =
destination;
const rcloneFlags = [
`--s3-access-key-id=${accessKey}`,
diff --git a/packages/server/src/utils/builders/compose.ts b/packages/server/src/utils/builders/compose.ts
index 19e7d152..ae181fc3 100644
--- a/packages/server/src/utils/builders/compose.ts
+++ b/packages/server/src/utils/builders/compose.ts
@@ -12,12 +12,8 @@ import {
writeDomainsToCompose,
writeDomainsToComposeRemote,
} from "../docker/domain";
-import {
- encodeBase64,
- getEnviromentVariablesObject,
- prepareEnvironmentVariables,
-} from "../docker/utils";
-import { execAsync, execAsyncRemote } from "../process/execAsync";
+import { encodeBase64, prepareEnvironmentVariables } from "../docker/utils";
+import { execAsyncRemote } from "../process/execAsync";
import { spawnAsync } from "../process/spawnAsync";
export type ComposeNested = InferResultType<
@@ -33,19 +29,13 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
await writeDomainsToCompose(compose, domains);
createEnvFile(compose);
- if (compose.isolatedDeployment) {
- await execAsync(
- `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}`,
- );
- }
-
const logContent = `
- App Name: ${appName}
- Build Compose 🐳
- Detected: ${mounts.length} mounts 📂
- Command: docker ${command}
- Source Type: docker ${sourceType} ✅
- Compose Type: ${composeType} ✅`;
+App Name: ${appName}
+Build Compose 🐳
+Detected: ${mounts.length} mounts 📂
+Command: docker ${command}
+Source Type: docker ${sourceType} ✅
+Compose Type: ${composeType} ✅`;
const logBox = boxen(logContent, {
padding: {
left: 1,
@@ -56,6 +46,7 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
borderStyle: "double",
});
writeStream.write(`\n${logBox}\n`);
+
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
await spawnAsync(
@@ -71,19 +62,10 @@ export const buildCompose = async (compose: ComposeNested, logPath: string) => {
env: {
NODE_ENV: process.env.NODE_ENV,
PATH: process.env.PATH,
- ...(composeType === "stack" && {
- ...getEnviromentVariablesObject(compose.env, compose.project.env),
- }),
},
},
);
- if (compose.isolatedDeployment) {
- await execAsync(
- `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1`,
- ).catch(() => {});
- }
-
writeStream.write("Docker Compose Deployed: ✅");
} catch (error) {
writeStream.write(`Error ❌ ${(error as Error).message}`);
@@ -98,11 +80,11 @@ export const getBuildComposeCommand = async (
logPath: string,
) => {
const { COMPOSE_PATH } = paths(true);
- const { sourceType, appName, mounts, composeType, domains } = compose;
+ const { sourceType, appName, mounts, composeType, domains, composePath } =
+ compose;
const command = createCommand(compose);
const envCommand = getCreateEnvFileCommand(compose);
const projectPath = join(COMPOSE_PATH, compose.appName, "code");
- const exportEnvCommand = getExportEnvCommand(compose);
const newCompose = await writeDomainsToComposeRemote(
compose,
@@ -138,10 +120,7 @@ Compose Type: ${composeType} ✅`;
cd "${projectPath}";
- ${exportEnvCommand}
- ${compose.isolatedDeployment ? `docker network inspect ${compose.appName} >/dev/null 2>&1 || docker network create --attachable ${compose.appName}` : ""}
docker ${command.split(" ").join(" ")} >> "${logPath}" 2>&1 || { echo "Error: ❌ Docker command failed" >> "${logPath}"; exit 1; }
- ${compose.isolatedDeployment ? `docker network connect ${compose.appName} $(docker ps --filter "name=dokploy-traefik" -q) >/dev/null 2>&1` : ""}
echo "Docker Compose Deployed: ✅" >> "${logPath}"
} || {
@@ -165,6 +144,7 @@ const sanitizeCommand = (command: string) => {
export const createCommand = (compose: ComposeNested) => {
const { composeType, appName, sourceType } = compose;
+
if (compose.command) {
return `${sanitizeCommand(compose.command)}`;
}
@@ -239,17 +219,3 @@ touch ${envFilePath};
echo "${encodedContent}" | base64 -d > "${envFilePath}";
`;
};
-
-const getExportEnvCommand = (compose: ComposeNested) => {
- if (compose.composeType !== "stack") return "";
-
- const envVars = getEnviromentVariablesObject(
- compose.env,
- compose.project.env,
- );
- const exports = Object.entries(envVars)
- .map(([key, value]) => `export ${key}=${JSON.stringify(value)}`)
- .join("\n");
-
- return exports ? `\n# Export environment variables\n${exports}\n` : "";
-};
diff --git a/packages/server/src/utils/builders/index.ts b/packages/server/src/utils/builders/index.ts
index d777b1a3..d6748275 100644
--- a/packages/server/src/utils/builders/index.ts
+++ b/packages/server/src/utils/builders/index.ts
@@ -197,7 +197,7 @@ export const mechanizeDockerContainer = async (
ForceUpdate: inspect.Spec.TaskTemplate.ForceUpdate + 1,
},
});
- } catch (_error) {
+ } catch (error) {
await docker.createService(settings);
}
};
diff --git a/packages/server/src/utils/builders/nixpacks.ts b/packages/server/src/utils/builders/nixpacks.ts
index c13f82a5..56560e4e 100644
--- a/packages/server/src/utils/builders/nixpacks.ts
+++ b/packages/server/src/utils/builders/nixpacks.ts
@@ -91,7 +91,7 @@ export const getNixpacksCommand = (
application: ApplicationNested,
logPath: string,
) => {
- const { env, appName, publishDirectory } = application;
+ const { env, appName, publishDirectory, serverId } = application;
const buildAppDirectory = getBuildAppDirectory(application);
const buildContainerId = `${appName}-${nanoid(10)}`;
diff --git a/packages/server/src/utils/databases/mariadb.ts b/packages/server/src/utils/databases/mariadb.ts
index ead5a618..d1b41fc3 100644
--- a/packages/server/src/utils/databases/mariadb.ts
+++ b/packages/server/src/utils/databases/mariadb.ts
@@ -98,7 +98,7 @@ export const buildMariadb = async (mariadb: MariadbNested) => {
version: Number.parseInt(inspect.Version.Index),
...settings,
});
- } catch (_error) {
+ } catch (error) {
await docker.createService(settings);
}
};
diff --git a/packages/server/src/utils/databases/mongo.ts b/packages/server/src/utils/databases/mongo.ts
index ace9c972..5af58eef 100644
--- a/packages/server/src/utils/databases/mongo.ts
+++ b/packages/server/src/utils/databases/mongo.ts
@@ -152,7 +152,7 @@ ${command ?? "wait $MONGOD_PID"}`;
version: Number.parseInt(inspect.Version.Index),
...settings,
});
- } catch (_error) {
+ } catch (error) {
await docker.createService(settings);
}
};
diff --git a/packages/server/src/utils/databases/mysql.ts b/packages/server/src/utils/databases/mysql.ts
index de28cfe6..5a691177 100644
--- a/packages/server/src/utils/databases/mysql.ts
+++ b/packages/server/src/utils/databases/mysql.ts
@@ -104,7 +104,7 @@ export const buildMysql = async (mysql: MysqlNested) => {
version: Number.parseInt(inspect.Version.Index),
...settings,
});
- } catch (_error) {
+ } catch (error) {
await docker.createService(settings);
}
};
diff --git a/packages/server/src/utils/databases/redis.ts b/packages/server/src/utils/databases/redis.ts
index aef86280..724069a1 100644
--- a/packages/server/src/utils/databases/redis.ts
+++ b/packages/server/src/utils/databases/redis.ts
@@ -95,7 +95,7 @@ export const buildRedis = async (redis: RedisNested) => {
version: Number.parseInt(inspect.Version.Index),
...settings,
});
- } catch (_error) {
+ } catch (error) {
await docker.createService(settings);
}
};
diff --git a/packages/server/src/utils/docker/collision.ts b/packages/server/src/utils/docker/collision.ts
deleted file mode 100644
index d3f131c6..00000000
--- a/packages/server/src/utils/docker/collision.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { findComposeById } from "@dokploy/server/services/compose";
-import { dump, load } from "js-yaml";
-import { addAppNameToAllServiceNames } from "./collision/root-network";
-import { generateRandomHash } from "./compose";
-import { addSuffixToAllVolumes } from "./compose/volume";
-import type { ComposeSpecification } from "./types";
-
-export const addAppNameToPreventCollision = (
- composeData: ComposeSpecification,
- appName: string,
-): ComposeSpecification => {
- let updatedComposeData = { ...composeData };
-
- updatedComposeData = addAppNameToAllServiceNames(updatedComposeData, appName);
- updatedComposeData = addSuffixToAllVolumes(updatedComposeData, appName);
- return updatedComposeData;
-};
-
-export const randomizeIsolatedDeploymentComposeFile = async (
- composeId: string,
- suffix?: string,
-) => {
- const compose = await findComposeById(composeId);
- const composeFile = compose.composeFile;
- const composeData = load(composeFile) as ComposeSpecification;
-
- const randomSuffix = suffix || compose.appName || generateRandomHash();
-
- const newComposeFile = addAppNameToPreventCollision(
- composeData,
- randomSuffix,
- );
-
- return dump(newComposeFile);
-};
-
-export const randomizeDeployableSpecificationFile = (
- composeSpec: ComposeSpecification,
- suffix?: string,
-) => {
- if (!suffix) {
- return composeSpec;
- }
- const newComposeFile = addAppNameToPreventCollision(composeSpec, suffix);
- return newComposeFile;
-};
diff --git a/packages/server/src/utils/docker/collision/root-network.ts b/packages/server/src/utils/docker/collision/root-network.ts
deleted file mode 100644
index ed36d4bd..00000000
--- a/packages/server/src/utils/docker/collision/root-network.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import _ from "lodash";
-import type { ComposeSpecification, DefinitionsService } from "../types";
-
-export const addAppNameToRootNetwork = (
- composeData: ComposeSpecification,
- appName: string,
-): ComposeSpecification => {
- const updatedComposeData = { ...composeData };
-
- // Initialize networks if it doesn't exist
- if (!updatedComposeData.networks) {
- updatedComposeData.networks = {};
- }
-
- // Add the new network with the app name
- updatedComposeData.networks[appName] = {
- name: appName,
- external: true,
- };
-
- return updatedComposeData;
-};
-
-export const addAppNameToServiceNetworks = (
- services: { [key: string]: DefinitionsService },
- appName: string,
-): { [key: string]: DefinitionsService } => {
- return _.mapValues(services, (service) => {
- if (!service.networks) {
- service.networks = [appName];
- return service;
- }
-
- if (Array.isArray(service.networks)) {
- if (!service.networks.includes(appName)) {
- service.networks.push(appName);
- }
- } else {
- service.networks[appName] = {};
- }
-
- return service;
- });
-};
-
-export const addAppNameToAllServiceNames = (
- composeData: ComposeSpecification,
- appName: string,
-): ComposeSpecification => {
- let updatedComposeData = { ...composeData };
-
- updatedComposeData = addAppNameToRootNetwork(updatedComposeData, appName);
-
- if (updatedComposeData.services) {
- updatedComposeData.services = addAppNameToServiceNetworks(
- updatedComposeData.services,
- appName,
- );
- }
-
- return updatedComposeData;
-};
diff --git a/packages/server/src/utils/docker/domain.ts b/packages/server/src/utils/docker/domain.ts
index c4ced3f4..69bfa222 100644
--- a/packages/server/src/utils/docker/domain.ts
+++ b/packages/server/src/utils/docker/domain.ts
@@ -26,7 +26,6 @@ import {
createComposeFileRaw,
createComposeFileRawRemote,
} from "../providers/raw";
-import { randomizeDeployableSpecificationFile } from "./collision";
import { randomizeSpecificationFile } from "./compose";
import type {
ComposeSpecification,
@@ -109,7 +108,7 @@ export const loadDockerComposeRemote = async (
if (!stdout) return null;
const parsedConfig = load(stdout) as ComposeSpecification;
return parsedConfig;
- } catch (_err) {
+ } catch (err) {
return null;
}
};
@@ -191,13 +190,7 @@ export const addDomainToCompose = async (
return null;
}
- if (compose.isolatedDeployment) {
- const randomized = randomizeDeployableSpecificationFile(
- result,
- compose.suffix || compose.appName,
- );
- result = randomized;
- } else if (compose.randomize) {
+ if (compose.randomize) {
const randomized = randomizeSpecificationFile(result, compose.suffix);
result = randomized;
}
@@ -210,6 +203,9 @@ export const addDomainToCompose = async (
if (!result?.services?.[serviceName]) {
throw new Error(`The service ${serviceName} not found in the compose`);
}
+ if (!result.services[serviceName].labels) {
+ result.services[serviceName].labels = [];
+ }
const httpLabels = await createDomainLabels(appName, domain, "web");
if (https) {
@@ -221,24 +217,7 @@ export const addDomainToCompose = async (
httpLabels.push(...httpsLabels);
}
- let labels: DefinitionsService["labels"] = [];
- if (compose.composeType === "docker-compose") {
- if (!result.services[serviceName].labels) {
- result.services[serviceName].labels = [];
- }
-
- labels = result.services[serviceName].labels;
- } else {
- // Stack Case
- if (!result.services[serviceName].deploy) {
- result.services[serviceName].deploy = {};
- }
- if (!result.services[serviceName].deploy.labels) {
- result.services[serviceName].deploy.labels = [];
- }
-
- labels = result.services[serviceName].deploy.labels;
- }
+ const labels = result.services[serviceName].labels;
if (Array.isArray(labels)) {
if (!labels.includes("traefik.enable=true")) {
@@ -247,18 +226,14 @@ export const addDomainToCompose = async (
labels.push(...httpLabels);
}
- if (!compose.isolatedDeployment) {
- // Add the dokploy-network to the service
- result.services[serviceName].networks = addDokployNetworkToService(
- result.services[serviceName].networks,
- );
- }
+ // Add the dokploy-network to the service
+ result.services[serviceName].networks = addDokployNetworkToService(
+ result.services[serviceName].networks,
+ );
}
// Add dokploy-network to the root of the compose file
- if (!compose.isolatedDeployment) {
- result.networks = addDokployNetworkToRoot(result.networks);
- }
+ result.networks = addDokployNetworkToRoot(result.networks);
return result;
};
diff --git a/packages/server/src/utils/docker/utils.ts b/packages/server/src/utils/docker/utils.ts
index 71b7e4aa..654d8330 100644
--- a/packages/server/src/utils/docker/utils.ts
+++ b/packages/server/src/utils/docker/utils.ts
@@ -100,7 +100,7 @@ export const containerExists = async (containerName: string) => {
try {
await container.inspect();
return true;
- } catch (_error) {
+ } catch (error) {
return false;
}
};
@@ -144,11 +144,10 @@ export const getContainerByName = (name: string): Promise => {
};
export const cleanUpUnusedImages = async (serverId?: string) => {
try {
- const command = "docker image prune --force";
if (serverId) {
- await execAsyncRemote(serverId, command);
+ await execAsyncRemote(serverId, "docker image prune --all --force");
} else {
- await execAsync(command);
+ await execAsync("docker image prune --all --force");
}
} catch (error) {
console.error(error);
@@ -158,11 +157,10 @@ export const cleanUpUnusedImages = async (serverId?: string) => {
export const cleanStoppedContainers = async (serverId?: string) => {
try {
- const command = "docker container prune --force";
if (serverId) {
- await execAsyncRemote(serverId, command);
+ await execAsyncRemote(serverId, "docker container prune --force");
} else {
- await execAsync(command);
+ await execAsync("docker container prune --force");
}
} catch (error) {
console.error(error);
@@ -172,11 +170,10 @@ export const cleanStoppedContainers = async (serverId?: string) => {
export const cleanUpUnusedVolumes = async (serverId?: string) => {
try {
- const command = "docker volume prune --force";
if (serverId) {
- await execAsyncRemote(serverId, command);
+ await execAsyncRemote(serverId, "docker volume prune --all --force");
} else {
- await execAsync(command);
+ await execAsync("docker volume prune --all --force");
}
} catch (error) {
console.error(error);
@@ -202,20 +199,21 @@ export const cleanUpInactiveContainers = async () => {
};
export const cleanUpDockerBuilder = async (serverId?: string) => {
- const command = "docker builder prune --all --force";
if (serverId) {
- await execAsyncRemote(serverId, command);
+ await execAsyncRemote(serverId, "docker builder prune --all --force");
} else {
- await execAsync(command);
+ await execAsync("docker builder prune --all --force");
}
};
export const cleanUpSystemPrune = async (serverId?: string) => {
- const command = "docker system prune --all --force --volumes";
if (serverId) {
- await execAsyncRemote(serverId, command);
+ await execAsyncRemote(
+ serverId,
+ "docker system prune --all --force --volumes",
+ );
} else {
- await execAsync(command);
+ await execAsync("docker system prune --all --force --volumes");
}
};
@@ -240,7 +238,7 @@ export const startServiceRemote = async (serverId: string, appName: string) => {
export const removeService = async (
appName: string,
serverId?: string | null,
- _deleteVolumes = false,
+ deleteVolumes = false,
) => {
try {
const command = `docker service rm ${appName}`;
@@ -278,15 +276,12 @@ export const prepareEnvironmentVariables = (
return resolvedVars;
};
-export const getEnviromentVariablesObject = (
- input: string | null,
- projectEnv?: string | null,
-) => {
- const envs = prepareEnvironmentVariables(input, projectEnv);
+export const prepareBuildArgs = (input: string | null) => {
+ const pairs = (input ?? "").split("\n");
const jsonObject: Record = {};
- for (const pair of envs) {
+ for (const pair of pairs) {
const [key, value] = pair.split("=");
if (key && value) {
jsonObject[key] = value;
diff --git a/packages/server/src/utils/gpu-setup.ts b/packages/server/src/utils/gpu-setup.ts
index a815a00c..6a6611b4 100644
--- a/packages/server/src/utils/gpu-setup.ts
+++ b/packages/server/src/utils/gpu-setup.ts
@@ -34,7 +34,7 @@ export async function checkGPUStatus(serverId?: string): Promise {
...gpuInfo,
...cudaInfo,
};
- } catch (_error) {
+ } catch (error) {
return {
driverInstalled: false,
driverVersion: undefined,
@@ -315,7 +315,7 @@ const setupLocalServer = async (daemonConfig: any) => {
try {
await execAsync(setupCommands);
- } catch (_error) {
+ } catch (error) {
throw new Error(
"Failed to configure GPU support. Please ensure you have sudo privileges and try again.",
);
diff --git a/packages/server/src/utils/notifications/build-error.ts b/packages/server/src/utils/notifications/build-error.ts
index c873c9ab..95936652 100644
--- a/packages/server/src/utils/notifications/build-error.ts
+++ b/packages/server/src/utils/notifications/build-error.ts
@@ -18,7 +18,7 @@ interface Props {
applicationType: string;
errorMessage: string;
buildLink: string;
- organizationId: string;
+ adminId: string;
}
export const sendBuildErrorNotifications = async ({
@@ -27,14 +27,14 @@ export const sendBuildErrorNotifications = async ({
applicationType,
errorMessage,
buildLink,
- organizationId,
+ adminId,
}: Props) => {
const date = new Date();
const unixDate = ~~(Number(date) / 1000);
const notificationList = await db.query.notifications.findMany({
where: and(
eq(notifications.appBuildError, true),
- eq(notifications.organizationId, organizationId),
+ eq(notifications.adminId, adminId),
),
with: {
email: true,
diff --git a/packages/server/src/utils/notifications/build-success.ts b/packages/server/src/utils/notifications/build-success.ts
index ac470c49..960f7a6a 100644
--- a/packages/server/src/utils/notifications/build-success.ts
+++ b/packages/server/src/utils/notifications/build-success.ts
@@ -18,7 +18,7 @@ interface Props {
applicationName: string;
applicationType: string;
buildLink: string;
- organizationId: string;
+ adminId: string;
domains: Domain[];
}
@@ -27,7 +27,7 @@ export const sendBuildSuccessNotifications = async ({
applicationName,
applicationType,
buildLink,
- organizationId,
+ adminId,
domains,
}: Props) => {
const date = new Date();
@@ -35,7 +35,7 @@ export const sendBuildSuccessNotifications = async ({
const notificationList = await db.query.notifications.findMany({
where: and(
eq(notifications.appDeploy, true),
- eq(notifications.organizationId, organizationId),
+ eq(notifications.adminId, adminId),
),
with: {
email: true,
diff --git a/packages/server/src/utils/notifications/database-backup.ts b/packages/server/src/utils/notifications/database-backup.ts
index 37a4a1ff..0b1d61f7 100644
--- a/packages/server/src/utils/notifications/database-backup.ts
+++ b/packages/server/src/utils/notifications/database-backup.ts
@@ -1,3 +1,4 @@
+import { error } from "node:console";
import { db } from "@dokploy/server/db";
import { notifications } from "@dokploy/server/db/schema";
import DatabaseBackupEmail from "@dokploy/server/emails/emails/database-backup";
@@ -18,13 +19,13 @@ export const sendDatabaseBackupNotifications = async ({
databaseType,
type,
errorMessage,
- organizationId,
+ adminId,
}: {
projectName: string;
applicationName: string;
databaseType: "postgres" | "mysql" | "mongodb" | "mariadb";
type: "error" | "success";
- organizationId: string;
+ adminId: string;
errorMessage?: string;
}) => {
const date = new Date();
@@ -32,7 +33,7 @@ export const sendDatabaseBackupNotifications = async ({
const notificationList = await db.query.notifications.findMany({
where: and(
eq(notifications.databaseBackup, true),
- eq(notifications.organizationId, organizationId),
+ eq(notifications.adminId, adminId),
),
with: {
email: true,
diff --git a/packages/server/src/utils/notifications/docker-cleanup.ts b/packages/server/src/utils/notifications/docker-cleanup.ts
index b3959ccc..b60e3b0a 100644
--- a/packages/server/src/utils/notifications/docker-cleanup.ts
+++ b/packages/server/src/utils/notifications/docker-cleanup.ts
@@ -13,7 +13,7 @@ import {
} from "./utils";
export const sendDockerCleanupNotifications = async (
- organizationId: string,
+ adminId: string,
message = "Docker cleanup for dokploy",
) => {
const date = new Date();
@@ -21,7 +21,7 @@ export const sendDockerCleanupNotifications = async (
const notificationList = await db.query.notifications.findMany({
where: and(
eq(notifications.dockerCleanup, true),
- eq(notifications.organizationId, organizationId),
+ eq(notifications.adminId, adminId),
),
with: {
email: true,
diff --git a/packages/server/src/utils/notifications/server-threshold.ts b/packages/server/src/utils/notifications/server-threshold.ts
deleted file mode 100644
index 2e63ba25..00000000
--- a/packages/server/src/utils/notifications/server-threshold.ts
+++ /dev/null
@@ -1,155 +0,0 @@
-import { and, eq } from "drizzle-orm";
-import { db } from "../../db";
-import { notifications } from "../../db/schema";
-import {
- sendDiscordNotification,
- sendSlackNotification,
- sendTelegramNotification,
-} from "./utils";
-
-interface ServerThresholdPayload {
- Type: "CPU" | "Memory";
- Value: number;
- Threshold: number;
- Message: string;
- Timestamp: string;
- Token: string;
- ServerName: string;
-}
-
-export const sendServerThresholdNotifications = async (
- organizationId: string,
- payload: ServerThresholdPayload,
-) => {
- const date = new Date(payload.Timestamp);
- const unixDate = ~~(Number(date) / 1000);
-
- const notificationList = await db.query.notifications.findMany({
- where: and(
- eq(notifications.serverThreshold, true),
- eq(notifications.organizationId, organizationId),
- ),
- with: {
- email: true,
- discord: true,
- telegram: true,
- slack: true,
- },
- });
-
- const typeEmoji = payload.Type === "CPU" ? "🔲" : "💾";
- const typeColor = 0xff0000; // Rojo para indicar alerta
-
- for (const notification of notificationList) {
- const { discord, telegram, slack } = notification;
-
- if (discord) {
- const decorate = (decoration: string, text: string) =>
- `${discord.decoration ? decoration : ""} ${text}`.trim();
-
- await sendDiscordNotification(discord, {
- title: decorate(">", `\`⚠️\` Server ${payload.Type} Alert`),
- color: typeColor,
- fields: [
- {
- name: decorate("`🏷️`", "Server Name"),
- value: payload.ServerName,
- inline: true,
- },
- {
- name: decorate("`📅`", "Date"),
- value: ``,
- inline: true,
- },
- {
- name: decorate("`⌚`", "Time"),
- value: ``,
- inline: true,
- },
- {
- name: decorate(typeEmoji, "Type"),
- value: payload.Type,
- inline: true,
- },
- {
- name: decorate("📊", "Current Value"),
- value: `${payload.Value.toFixed(2)}%`,
- inline: true,
- },
- {
- name: decorate("⚠️", "Threshold"),
- value: `${payload.Threshold.toFixed(2)}%`,
- inline: true,
- },
- {
- name: decorate("`📜`", "Message"),
- value: `\`\`\`${payload.Message}\`\`\``,
- },
- ],
- timestamp: date.toISOString(),
- footer: {
- text: "Dokploy Server Monitoring Alert",
- },
- });
- }
-
- if (telegram) {
- await sendTelegramNotification(
- telegram,
- `
- ⚠️ Server ${payload.Type} Alert
- Server Name: ${payload.ServerName}
- Type: ${payload.Type}
- Current Value: ${payload.Value.toFixed(2)}%
- Threshold: ${payload.Threshold.toFixed(2)}%
- Message: ${payload.Message}
- Time: ${date.toLocaleString()}
- `,
- );
- }
-
- if (slack) {
- const { channel } = slack;
- await sendSlackNotification(slack, {
- channel: channel,
- attachments: [
- {
- color: "#FF0000",
- pretext: `:warning: *Server ${payload.Type} Alert*`,
- fields: [
- {
- title: "Server Name",
- value: payload.ServerName,
- short: true,
- },
- {
- title: "Type",
- value: payload.Type,
- short: true,
- },
- {
- title: "Current Value",
- value: `${payload.Value.toFixed(2)}%`,
- short: true,
- },
- {
- title: "Threshold",
- value: `${payload.Threshold.toFixed(2)}%`,
- short: true,
- },
- {
- title: "Message",
- value: payload.Message,
- },
- {
- title: "Time",
- value: date.toLocaleString(),
- short: true,
- },
- ],
- },
- ],
- });
- }
- }
-};
diff --git a/packages/server/src/utils/notifications/utils.ts b/packages/server/src/utils/notifications/utils.ts
index dd552cf3..4f8bb1a5 100644
--- a/packages/server/src/utils/notifications/utils.ts
+++ b/packages/server/src/utils/notifications/utils.ts
@@ -68,7 +68,6 @@ export const sendTelegramNotification = async (
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
chat_id: connection.chatId,
- message_thread_id: connection.messageThreadId,
text: messageText,
parse_mode: "HTML",
disable_web_page_preview: true,
diff --git a/packages/server/src/utils/process/execAsync.ts b/packages/server/src/utils/process/execAsync.ts
index aee1e821..19a16ac1 100644
--- a/packages/server/src/utils/process/execAsync.ts
+++ b/packages/server/src/utils/process/execAsync.ts
@@ -27,7 +27,7 @@ export const execAsyncRemote = async (
throw err;
}
stream
- .on("close", (code: number, _signal: string) => {
+ .on("close", (code: number, signal: string) => {
conn.end();
if (code === 0) {
resolve({ stdout, stderr });
diff --git a/packages/server/src/utils/providers/bitbucket.ts b/packages/server/src/utils/providers/bitbucket.ts
index dd98a93b..7059e65f 100644
--- a/packages/server/src/utils/providers/bitbucket.ts
+++ b/packages/server/src/utils/providers/bitbucket.ts
@@ -176,6 +176,7 @@ export const getBitbucketCloneCommand = async (
bitbucketBranch,
bitbucketId,
serverId,
+ bitbucket,
} = entity;
if (!serverId) {
diff --git a/packages/server/src/utils/providers/git.ts b/packages/server/src/utils/providers/git.ts
index c26af3af..6377b557 100644
--- a/packages/server/src/utils/providers/git.ts
+++ b/packages/server/src/utils/providers/git.ts
@@ -69,7 +69,6 @@ export const cloneGitRepository = async (
});
}
- const { port } = sanitizeRepoPathSSH(customGitUrl);
await spawnAsync(
"git",
[
@@ -92,7 +91,7 @@ export const cloneGitRepository = async (
env: {
...process.env,
...(customGitSSHKeyId && {
- GIT_SSH_COMMAND: `ssh -i ${temporalKeyPath}${port ? ` -p ${port}` : ""} -o UserKnownHostsFile=${knownHostsPath}`,
+ GIT_SSH_COMMAND: `ssh -i ${temporalKeyPath} -o UserKnownHostsFile=${knownHostsPath}`,
}),
},
},
@@ -169,8 +168,7 @@ export const getCustomGitCloneCommand = async (
);
if (customGitSSHKeyId) {
const sshKey = await findSSHKeyById(customGitSSHKeyId);
- const { port } = sanitizeRepoPathSSH(customGitUrl);
- const gitSshCommand = `ssh -i /tmp/id_rsa${port ? ` -p ${port}` : ""} -o UserKnownHostsFile=${knownHostsPath}`;
+ const gitSshCommand = `ssh -i /tmp/id_rsa -o UserKnownHostsFile=${knownHostsPath}`;
command.push(
`
echo "${sshKey.privateKey}" > /tmp/id_rsa
@@ -306,7 +304,6 @@ export const cloneGitRawRepository = async (entity: {
});
}
- const { port } = sanitizeRepoPathSSH(customGitUrl);
await spawnAsync(
"git",
[
@@ -320,12 +317,12 @@ export const cloneGitRawRepository = async (entity: {
outputPath,
"--progress",
],
- (_data) => {},
+ (data) => {},
{
env: {
...process.env,
...(customGitSSHKeyId && {
- GIT_SSH_COMMAND: `ssh -i ${temporalKeyPath}${port ? ` -p ${port}` : ""} -o UserKnownHostsFile=${knownHostsPath}`,
+ GIT_SSH_COMMAND: `ssh -i ${temporalKeyPath} -o UserKnownHostsFile=${knownHostsPath}`,
}),
},
},
@@ -384,8 +381,7 @@ export const cloneRawGitRepositoryRemote = async (compose: Compose) => {
command.push(`mkdir -p ${outputPath};`);
if (customGitSSHKeyId) {
const sshKey = await findSSHKeyById(customGitSSHKeyId);
- const { port } = sanitizeRepoPathSSH(customGitUrl);
- const gitSshCommand = `ssh -i /tmp/id_rsa${port ? ` -p ${port}` : ""} -o UserKnownHostsFile=${knownHostsPath}`;
+ const gitSshCommand = `ssh -i /tmp/id_rsa -o UserKnownHostsFile=${knownHostsPath}`;
command.push(
`
echo "${sshKey.privateKey}" > /tmp/id_rsa
diff --git a/packages/server/src/utils/providers/gitlab.ts b/packages/server/src/utils/providers/gitlab.ts
index c380a920..096f9e28 100644
--- a/packages/server/src/utils/providers/gitlab.ts
+++ b/packages/server/src/utils/providers/gitlab.ts
@@ -162,6 +162,8 @@ export const getGitlabCloneCommand = async (
) => {
const {
appName,
+ gitlabRepository,
+ gitlabOwner,
gitlabPathNamespace,
gitlabBranch,
gitlabId,
@@ -266,7 +268,7 @@ export const getGitlabRepositories = async (gitlabId?: string) => {
if (groupName) {
return full_path.toLowerCase().includes(groupName) && kind === "group";
}
- return kind === "member";
+ return kind === "user";
});
const mappedRepositories = filteredRepos.map((repo: any) => {
return {
@@ -326,7 +328,14 @@ export const getGitlabBranches = async (input: {
};
export const cloneRawGitlabRepository = async (entity: Compose) => {
- const { appName, gitlabBranch, gitlabId, gitlabPathNamespace } = entity;
+ const {
+ appName,
+ gitlabRepository,
+ gitlabOwner,
+ gitlabBranch,
+ gitlabId,
+ gitlabPathNamespace,
+ } = entity;
if (!gitlabId) {
throw new TRPCError({
@@ -433,7 +442,7 @@ export const testGitlabConnection = async (
if (groupName) {
return full_path.toLowerCase().includes(groupName) && kind === "group";
}
- return kind === "member";
+ return kind === "user";
});
return filteredRepos.length;
diff --git a/packages/server/src/utils/traefik/application.ts b/packages/server/src/utils/traefik/application.ts
index 61150abf..4434d858 100644
--- a/packages/server/src/utils/traefik/application.ts
+++ b/packages/server/src/utils/traefik/application.ts
@@ -67,7 +67,7 @@ export const removeTraefikConfig = async (
if (fs.existsSync(configPath)) {
await fs.promises.unlink(configPath);
}
- } catch (_error) {}
+ } catch (error) {}
};
export const removeTraefikConfigRemote = async (
@@ -78,7 +78,7 @@ export const removeTraefikConfigRemote = async (
const { DYNAMIC_TRAEFIK_PATH } = paths(true);
const configPath = path.join(DYNAMIC_TRAEFIK_PATH, `${appName}.yml`);
await execAsyncRemote(serverId, `rm ${configPath}`);
- } catch (_error) {}
+ } catch (error) {}
};
export const loadOrCreateConfig = (appName: string): FileConfig => {
@@ -110,7 +110,7 @@ export const loadOrCreateConfigRemote = async (
http: { routers: {}, services: {} },
};
return parsedConfig;
- } catch (_err) {
+ } catch (err) {
return fileConfig;
}
};
@@ -132,7 +132,7 @@ export const readRemoteConfig = async (serverId: string, appName: string) => {
const { stdout } = await execAsyncRemote(serverId, `cat ${configPath}`);
if (!stdout) return null;
return stdout;
- } catch (_err) {
+ } catch (err) {
return null;
}
};
diff --git a/packages/server/src/utils/traefik/domain.ts b/packages/server/src/utils/traefik/domain.ts
index 1ae3c05a..a6c878e7 100644
--- a/packages/server/src/utils/traefik/domain.ts
+++ b/packages/server/src/utils/traefik/domain.ts
@@ -122,25 +122,13 @@ export const createRouterConfig = async (
if ((entryPoint === "websecure" && https) || !https) {
// redirects
for (const redirect of redirects) {
- let middlewareName = `redirect-${appName}-${redirect.uniqueConfigKey}`;
- if (domain.domainType === "preview") {
- middlewareName = `redirect-${appName.replace(
- /^preview-(.+)-[^-]+$/,
- "$1",
- )}-${redirect.uniqueConfigKey}`;
- }
+ const middlewareName = `redirect-${appName}-${redirect.uniqueConfigKey}`;
routerConfig.middlewares?.push(middlewareName);
}
// security
if (security.length > 0) {
- let middlewareName = `auth-${appName}`;
- if (domain.domainType === "preview") {
- middlewareName = `auth-${appName.replace(
- /^preview-(.+)-[^-]+$/,
- "$1",
- )}`;
- }
+ const middlewareName = `auth-${appName}`;
routerConfig.middlewares?.push(middlewareName);
}
}
diff --git a/packages/server/src/utils/traefik/middleware.ts b/packages/server/src/utils/traefik/middleware.ts
index 934d637e..60345f66 100644
--- a/packages/server/src/utils/traefik/middleware.ts
+++ b/packages/server/src/utils/traefik/middleware.ts
@@ -95,7 +95,7 @@ export const loadRemoteMiddlewares = async (serverId: string) => {
}
const config = load(stdout) as FileConfig;
return config;
- } catch (_) {
+ } catch (error) {
throw new Error(`File not found: ${configPath}`);
}
};
diff --git a/packages/server/src/utils/traefik/web-server.ts b/packages/server/src/utils/traefik/web-server.ts
index 78046c67..0aa4d35d 100644
--- a/packages/server/src/utils/traefik/web-server.ts
+++ b/packages/server/src/utils/traefik/web-server.ts
@@ -1,14 +1,14 @@
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { paths } from "@dokploy/server/constants";
-import type { User } from "@dokploy/server/services/user";
+import type { Admin } from "@dokploy/server/services/admin";
import { dump, load } from "js-yaml";
import { loadOrCreateConfig, writeTraefikConfig } from "./application";
import type { FileConfig } from "./file-types";
import type { MainTraefikConfig } from "./types";
export const updateServerTraefik = (
- user: User | null,
+ admin: Admin | null,
newHost: string | null,
) => {
const appName = "dokploy";
@@ -22,7 +22,7 @@ export const updateServerTraefik = (
if (currentRouterConfig && newHost) {
currentRouterConfig.rule = `Host(\`${newHost}\`)`;
- if (user?.certificateType === "letsencrypt") {
+ if (admin?.certificateType === "letsencrypt") {
config.http.routers[`${appName}-router-app-secure`] = {
...currentRouterConfig,
entryPoints: ["websecure"],
diff --git a/packages/server/src/verification/send-verification-email.tsx b/packages/server/src/verification/send-verification-email.tsx
deleted file mode 100644
index c673c0f7..00000000
--- a/packages/server/src/verification/send-verification-email.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import {
- sendDiscordNotification,
- sendEmailNotification,
-} from "../utils/notifications/utils";
-export const sendEmail = async ({
- email,
- subject,
- text,
-}: {
- email: string;
- subject: string;
- text: string;
-}) => {
- await sendEmailNotification(
- {
- fromAddress: process.env.SMTP_FROM_ADDRESS || "",
- toAddresses: [email],
- smtpServer: process.env.SMTP_SERVER || "",
- smtpPort: Number(process.env.SMTP_PORT),
- username: process.env.SMTP_USERNAME || "",
- password: process.env.SMTP_PASSWORD || "",
- },
- subject,
- text,
- );
-
- return true;
-};
-
-export const sendDiscordNotificationWelcome = async (email: string) => {
- await sendDiscordNotification(
- {
- webhookUrl: process.env.DISCORD_WEBHOOK_URL || "",
- },
- {
- title: "New User Registered",
- color: 0x00ff00,
- fields: [
- {
- name: "Email",
- value: email,
- inline: true,
- },
- ],
- timestamp: new Date(),
- footer: {
- text: "Dokploy User Registration Notification",
- },
- },
- );
-};
diff --git a/packages/server/tsconfig.server.json b/packages/server/tsconfig.server.json
index 33777c02..7f349eb8 100644
--- a/packages/server/tsconfig.server.json
+++ b/packages/server/tsconfig.server.json
@@ -1,7 +1,6 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
- "disableSizeLimit": true,
"module": "ESNext",
"outDir": "dist/",
"target": "ESNext",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 703101ec..7542278f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,7 +17,7 @@ importers:
version: 1.9.4
'@commitlint/cli':
specifier: ^19.3.0
- version: 19.3.0(@types/node@18.19.42)(typescript@5.7.2)
+ version: 19.3.0(@types/node@18.19.42)(typescript@5.5.3)
'@commitlint/config-conventional':
specifier: ^19.2.2
version: 19.2.2
@@ -127,12 +127,6 @@ importers:
'@hookform/resolvers':
specifier: ^3.9.0
version: 3.9.0(react-hook-form@7.52.1(react@18.2.0))
- '@lucia-auth/adapter-drizzle':
- specifier: 1.0.7
- version: 1.0.7(lucia@3.2.0)
- '@octokit/auth-app':
- specifier: ^6.0.4
- version: 6.1.1
'@octokit/webhooks':
specifier: ^13.2.7
version: 13.3.0
@@ -193,9 +187,6 @@ importers:
'@radix-ui/react-tooltip':
specifier: ^1.0.7
version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
- '@react-email/components':
- specifier: ^0.0.21
- version: 0.0.21(@types/react@18.3.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@stepperize/react':
specifier: 4.0.1
version: 4.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -229,9 +220,6 @@ importers:
'@xterm/addon-attach':
specifier: 0.10.0
version: 0.10.0(@xterm/xterm@5.5.0)
- '@xterm/addon-clipboard':
- specifier: 0.1.0
- version: 0.1.0(@xterm/xterm@5.5.0)
'@xterm/xterm':
specifier: ^5.4.0
version: 5.5.0
@@ -243,16 +231,7 @@ importers:
version: 4.0.31(react@18.2.0)(zod@3.23.8)
bcrypt:
specifier: 5.1.1
- version: 5.1.1(encoding@0.1.13)
- better-auth:
- specifier: 1.2.0
- version: 1.2.0(typescript@5.5.3)
- bl:
- specifier: 6.0.11
- version: 6.0.11
- boxen:
- specifier: ^7.1.1
- version: 7.1.1
+ version: 5.1.1
bullmq:
specifier: 5.4.2
version: 5.4.2
@@ -274,24 +253,18 @@ importers:
date-fns:
specifier: 3.6.0
version: 3.6.0
- dockerode:
- specifier: 4.0.2
- version: 4.0.2
dotenv:
specifier: 16.4.5
version: 16.4.5
drizzle-orm:
- specifier: ^0.39.1
- version: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7)
+ specifier: ^0.30.8
+ version: 0.30.10(@opentelemetry/api@1.9.0)(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)
drizzle-zod:
specifier: 0.5.1
- version: 0.5.1(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))(zod@3.23.8)
+ version: 0.5.1(drizzle-orm@0.30.10(@opentelemetry/api@1.9.0)(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0))(zod@3.23.8)
fancy-ansi:
specifier: ^0.1.3
version: 0.1.3
- hi-base32:
- specifier: ^0.5.1
- version: 0.5.1
i18next:
specifier: ^23.16.4
version: 23.16.5
@@ -324,43 +297,28 @@ importers:
version: 15.3.1(i18next@23.16.5)(next@15.0.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-i18next@15.1.1(i18next@23.16.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react@18.2.0)
next-themes:
specifier: ^0.2.1
- version: 0.2.1(next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
- node-os-utils:
- specifier: 1.3.7
- version: 1.3.7
+ version: 0.2.1(next@15.0.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
node-pty:
specifier: 1.0.0
version: 1.0.0
node-schedule:
specifier: 2.1.1
version: 2.1.1
- nodemailer:
- specifier: 6.9.14
- version: 6.9.14
octokit:
specifier: 3.1.2
version: 3.1.2
- otpauth:
- specifier: ^9.2.3
- version: 9.3.4
postgres:
specifier: 3.4.4
version: 3.4.4
public-ip:
specifier: 6.0.2
version: 6.0.2
- qrcode:
- specifier: ^1.5.3
- version: 1.5.4
react:
specifier: 18.2.0
version: 18.2.0
react-confetti-explosion:
specifier: 2.1.2
version: 2.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
- react-day-picker:
- specifier: 8.10.1
- version: 8.10.1(date-fns@3.6.0)(react@18.2.0)
react-dom:
specifier: 18.2.0
version: 18.2.0(react@18.2.0)
@@ -376,9 +334,6 @@ importers:
recharts:
specifier: ^2.12.7
version: 2.12.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
- rotating-file-stream:
- specifier: 3.2.3
- version: 3.2.3
slugify:
specifier: ^1.6.6
version: 1.6.6
@@ -402,7 +357,7 @@ importers:
version: 2.4.0
tailwindcss-animate:
specifier: ^1.0.7
- version: 1.0.7(tailwindcss@3.4.7(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.3)))
+ version: 1.0.7(tailwindcss@3.4.7)
undici:
specifier: ^6.19.2
version: 6.19.4
@@ -443,18 +398,9 @@ importers:
'@types/node':
specifier: ^18.17.0
version: 18.19.42
- '@types/node-os-utils':
- specifier: 1.3.4
- version: 1.3.4
'@types/node-schedule':
specifier: 2.1.6
version: 2.1.6
- '@types/nodemailer':
- specifier: ^6.4.15
- version: 6.4.16
- '@types/qrcode':
- specifier: ^1.5.5
- version: 1.5.5
'@types/react':
specifier: 18.3.5
version: 18.3.5
@@ -474,8 +420,8 @@ importers:
specifier: 10.4.12
version: 10.4.12(postcss@8.4.40)
drizzle-kit:
- specifier: ^0.30.4
- version: 0.30.4
+ specifier: ^0.21.1
+ version: 0.21.4
esbuild:
specifier: 0.20.2
version: 0.20.2
@@ -487,7 +433,7 @@ importers:
version: 4.11.0
tailwindcss:
specifier: ^3.4.1
- version: 3.4.7(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.3))
+ version: 3.4.7
tsx:
specifier: ^4.7.0
version: 4.16.2
@@ -519,8 +465,8 @@ importers:
specifier: ^16.3.1
version: 16.4.5
drizzle-orm:
- specifier: ^0.39.1
- version: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7)
+ specifier: ^0.30.8
+ version: 0.30.10(@opentelemetry/api@1.9.0)(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)
hono:
specifier: ^4.5.8
version: 4.5.8
@@ -561,9 +507,27 @@ importers:
packages/server:
dependencies:
- '@better-auth/utils':
- specifier: 0.2.3
- version: 0.2.3
+ '@ai-sdk/anthropic':
+ specifier: ^1.0.6
+ version: 1.0.8(zod@3.23.8)
+ '@ai-sdk/azure':
+ specifier: ^1.0.15
+ version: 1.0.18(zod@3.23.8)
+ '@ai-sdk/cohere':
+ specifier: ^1.0.6
+ version: 1.0.8(zod@3.23.8)
+ '@ai-sdk/deepinfra':
+ specifier: ^0.0.4
+ version: 0.0.4(zod@3.23.8)
+ '@ai-sdk/mistral':
+ specifier: ^1.0.6
+ version: 1.0.8(zod@3.23.8)
+ '@ai-sdk/openai':
+ specifier: ^1.0.12
+ version: 1.0.16(zod@3.23.8)
+ '@ai-sdk/openai-compatible':
+ specifier: ^0.0.13
+ version: 0.0.13(zod@3.23.8)
'@faker-js/faker':
specifier: ^8.4.1
version: 8.4.1
@@ -573,12 +537,6 @@ importers:
'@octokit/auth-app':
specifier: ^6.0.4
version: 6.1.1
- '@oslojs/crypto':
- specifier: 1.0.1
- version: 1.0.1
- '@oslojs/encoding':
- specifier: 1.1.0
- version: 1.1.0
'@react-email/components':
specifier: ^0.0.21
version: 0.0.21(@types/react@18.3.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -593,10 +551,7 @@ importers:
version: 4.0.31(react@18.2.0)(zod@3.23.8)
bcrypt:
specifier: 5.1.1
- version: 5.1.1(encoding@0.1.13)
- better-auth:
- specifier: 1.2.0
- version: 1.2.0(typescript@5.5.3)
+ version: 5.1.1
bl:
specifier: 6.0.11
version: 6.0.11
@@ -612,15 +567,12 @@ importers:
dotenv:
specifier: 16.4.5
version: 16.4.5
- drizzle-dbml-generator:
- specifier: 0.10.0
- version: 0.10.0(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))
drizzle-orm:
- specifier: ^0.39.1
- version: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7)
+ specifier: ^0.30.8
+ version: 0.30.10(@opentelemetry/api@1.9.0)(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)
drizzle-zod:
specifier: 0.5.1
- version: 0.5.1(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))(zod@3.23.8)
+ version: 0.5.1(drizzle-orm@0.30.10(@opentelemetry/api@1.9.0)(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0))(zod@3.23.8)
hi-base32:
specifier: ^0.5.1
version: 0.5.1
@@ -731,8 +683,8 @@ importers:
specifier: 8.5.10
version: 8.5.10
drizzle-kit:
- specifier: ^0.30.4
- version: 0.30.4
+ specifier: ^0.21.1
+ version: 0.21.4
esbuild:
specifier: 0.20.2
version: 0.20.2
@@ -744,7 +696,7 @@ importers:
version: 8.4.40
tailwindcss:
specifier: ^3.4.1
- version: 3.4.7(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.3))
+ version: 3.4.7
tsc-alias:
specifier: 1.8.10
version: 1.8.10
@@ -873,12 +825,6 @@ packages:
'@balena/dockerignore@1.0.2':
resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==}
- '@better-auth/utils@0.2.3':
- resolution: {integrity: sha512-Ap1GaSmo6JYhJhxJOpUB0HobkKPTNzfta+bLV89HfpyCAHN7p8ntCrmNFHNAVD0F6v0mywFVEUg1FUhNCc81Rw==}
-
- '@better-fetch/fetch@1.1.15':
- resolution: {integrity: sha512-0Bl8YYj1f8qCTNHeSn5+1DWv2hy7rLBrQ8rS8Y9XYloiwZEfc3k4yspIG0llRxafxqhGCwlGRg+F8q1HZRCMXA==}
-
'@biomejs/biome@1.9.4':
resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==}
engines: {node: '>=14.21.3'}
@@ -1042,19 +988,12 @@ packages:
resolution: {integrity: sha512-tpyc+7i6bPG9mvaBbtKUeghfyZSDgWquIDfMgqYtTbmZ9Y9VzEm2je9EYcQ0aoz5o7NvGS+rcDec93yO08MHYA==}
engines: {node: '>=v18'}
- '@cspotcode/source-map-support@0.8.1':
- resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
- engines: {node: '>=12'}
-
'@dokploy/trpc-openapi@0.0.4':
resolution: {integrity: sha512-a7VKunKu9arq57bP9MPH7ikJuKfT5SILnNy70vMqf1stm5IrqMG3Y7CIFprFe0DZiw3bwjue0KpETIATBftN6w==}
peerDependencies:
'@trpc/server': ^10.0.0
zod: ^3.14.4
- '@drizzle-team/brocli@0.10.2':
- resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
-
'@emnapi/core@0.45.0':
resolution: {integrity: sha512-DPWjcUDQkCeEM4VnljEOEcXdAD7pp8zSZsgOujk/LGIwCXWbXJngin+MO4zbH429lzeC3WbYLGjE2MaUOwzpyw==}
@@ -1643,15 +1582,9 @@ packages:
'@floating-ui/utils@0.2.5':
resolution: {integrity: sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ==}
- '@gar/promisify@1.1.3':
- resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
-
'@hapi/bourne@3.0.0':
resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==}
- '@hexagon/base64@1.1.28':
- resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==}
-
'@hono/node-server@1.12.1':
resolution: {integrity: sha512-C9l+08O8xtXB7Ppmy8DjBFH1hYji7JKzsU32Yt1poIIbdPp6S7aOI8IldDHD9YFJ55lv2c21ovNrmxatlHfhAg==}
engines: {node: '>=18.14.1'}
@@ -1804,9 +1737,6 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
- '@jridgewell/trace-mapping@0.3.9':
- resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
-
'@jsonjoy.com/base64@1.1.2':
resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==}
engines: {node: '>=10.0'}
@@ -1831,9 +1761,6 @@ packages:
'@leichtgewicht/ip-codec@2.0.5':
resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==}
- '@levischuck/tiny-cbor@0.2.11':
- resolution: {integrity: sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==}
-
'@lezer/common@1.2.1':
resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==}
@@ -1944,17 +1871,10 @@ packages:
cpu: [x64]
os: [win32]
- '@noble/ciphers@0.6.0':
- resolution: {integrity: sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ==}
-
'@noble/hashes@1.5.0':
resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==}
engines: {node: ^14.21.3 || >=16}
- '@noble/hashes@1.7.1':
- resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==}
- engines: {node: ^14.21.3 || >=16}
-
'@node-rs/argon2-android-arm-eabi@1.7.0':
resolution: {integrity: sha512-udDqkr5P9E+wYX1SZwAVPdyfYvaF4ry9Tm+R9LkfSHbzWH0uhU6zjIwNRp7m+n4gx691rk+lqqDAIP8RLKwbhg==}
engines: {node: '>= 10'}
@@ -2141,14 +2061,6 @@ packages:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
- '@npmcli/fs@1.1.1':
- resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==}
-
- '@npmcli/move-file@1.1.2':
- resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==}
- engines: {node: '>=10'}
- deprecated: This functionality has been moved to @npmcli/fs
-
'@octokit/app@14.1.0':
resolution: {integrity: sha512-g3uEsGOQCBl1+W1rgfwoRFUIR6PtvB2T1E4RpygeUU5LrLvlOqcxrt5lfykIeRpUPpupreGJUYl70fqMDXdTpw==}
engines: {node: '>= 18'}
@@ -2280,32 +2192,9 @@ packages:
'@one-ini/wasm@0.1.1':
resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
- '@oslojs/asn1@1.0.0':
- resolution: {integrity: sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==}
-
- '@oslojs/binary@1.0.0':
- resolution: {integrity: sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==}
-
- '@oslojs/crypto@1.0.1':
- resolution: {integrity: sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==}
-
- '@oslojs/encoding@1.1.0':
- resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==}
-
- '@peculiar/asn1-android@2.3.15':
- resolution: {integrity: sha512-8U2TIj59cRlSXTX2d0mzUKP7whfWGFMzTeC3qPgAbccXFrPNZLaDhpNEdG5U2QZ/tBv/IHlCJ8s+KYXpJeop6w==}
-
- '@peculiar/asn1-ecc@2.3.15':
- resolution: {integrity: sha512-/HtR91dvgog7z/WhCVdxZJ/jitJuIu8iTqiyWVgRE9Ac5imt2sT/E4obqIVGKQw7PIy+X6i8lVBoT6wC73XUgA==}
-
- '@peculiar/asn1-rsa@2.3.15':
- resolution: {integrity: sha512-p6hsanvPhexRtYSOHihLvUUgrJ8y0FtOM97N5UEpC+VifFYyZa0iZ5cXjTkZoDwxJ/TTJ1IJo3HVTB2JJTpXvg==}
-
- '@peculiar/asn1-schema@2.3.15':
- resolution: {integrity: sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==}
-
- '@peculiar/asn1-x509@2.3.15':
- resolution: {integrity: sha512-0dK5xqTqSLaxv1FHXIcd4Q/BZNuopg+u1l23hT9rOmQ1g4dNtw0g/RnEi+TboB0gOwGtrWn269v27cMgchFIIg==}
+ '@opentelemetry/api@1.9.0':
+ resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
+ engines: {node: '>=8.0.0'}
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
@@ -3318,13 +3207,6 @@ packages:
'@selderee/plugin-htmlparser2@0.11.0':
resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==}
- '@simplewebauthn/browser@13.1.0':
- resolution: {integrity: sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==}
-
- '@simplewebauthn/server@13.1.1':
- resolution: {integrity: sha512-1hsLpRHfSuMB9ee2aAdh0Htza/X3f4djhYISrggqGe3xopNjOcePiSDkDDoPzDYaaMCrbqGP1H2TYU7bgL9PmA==}
- engines: {node: '>=20.0.0'}
-
'@sinclair/typebox@0.27.8':
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
@@ -3471,10 +3353,6 @@ packages:
resolution: {integrity: sha512-IqREj9ADoml9zCAouIG/5kCGoyIxPFdqdyoxis9FisXFi5vT+iYfEfLosq4xkU/iDbMcEuAj+X8dWRLvKYDNoQ==}
engines: {node: '>=12'}
- '@tootallnate/once@1.1.2':
- resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==}
- engines: {node: '>= 6'}
-
'@trpc/client@10.45.2':
resolution: {integrity: sha512-ykALM5kYWTLn1zYuUOZ2cPWlVfrXhc18HzBDyRhoPYN0jey4iQHEFSEowfnhg1RvYnrAVjNBgHNeSAXjrDbGwg==}
peerDependencies:
@@ -3503,18 +3381,6 @@ packages:
'@trpc/server@10.45.2':
resolution: {integrity: sha512-wOrSThNNE4HUnuhJG6PfDRp4L2009KDVxsd+2VYH8ro6o/7/jwYZ8Uu5j+VaW+mOmc8EHerHzGcdbGNQSAUPgg==}
- '@tsconfig/node10@1.0.11':
- resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
-
- '@tsconfig/node12@1.0.11':
- resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
-
- '@tsconfig/node14@1.0.3':
- resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
-
- '@tsconfig/node16@1.0.4':
- resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
-
'@tybys/wasm-util@0.8.3':
resolution: {integrity: sha512-Z96T/L6dUFFxgFJ+pQtkPpne9q7i6kIPYCFnQBHSgSPV9idTsKfIhCss0h5iM9irweZCatkrdeP8yi5uM1eX6Q==}
@@ -3798,11 +3664,6 @@ packages:
peerDependencies:
'@xterm/xterm': ^5.0.0
- '@xterm/addon-clipboard@0.1.0':
- resolution: {integrity: sha512-zdoM7p53T5sv/HbRTyp4hY0kKmEQ3MZvAvEtiXqNIHc/JdpqwByCtsTaQF5DX2n4hYdXRPO4P/eOS0QEhX1nPw==}
- peerDependencies:
- '@xterm/xterm': ^5.4.0
-
'@xterm/xterm@5.5.0':
resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==}
@@ -3853,10 +3714,6 @@ packages:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
- agentkeepalive@4.6.0:
- resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
- engines: {node: '>= 8.0.0'}
-
aggregate-error@3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
engines: {node: '>=8'}
@@ -3950,14 +3807,6 @@ packages:
engines: {node: '>=10'}
deprecated: This package is no longer supported.
- are-we-there-yet@3.0.1:
- resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- deprecated: This package is no longer supported.
-
- arg@4.1.3:
- resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
-
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
@@ -3981,10 +3830,6 @@ packages:
asn1@0.2.6:
resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
- asn1js@3.0.5:
- resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==}
- engines: {node: '>=12.0.0'}
-
assertion-error@1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
@@ -4030,19 +3875,10 @@ packages:
before-after-hook@2.2.3:
resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==}
- better-auth@1.2.0:
- resolution: {integrity: sha512-eIRGOXfix25bh4fgs8jslZAZssufpIkxfEeEokQu5G4wICoDee1wPctkFb8v80PvhtI4dPm28SuAoZaAdRc6Wg==}
-
- better-call@1.0.3:
- resolution: {integrity: sha512-DUKImKoDIy5UtCvQbHTg0wuBRse6gu1Yvznn7+1B3I5TeY8sclRPFce0HI+4WF2bcb+9PqmkET8nXZubrHQh9A==}
-
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
- bindings@1.5.0:
- resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
-
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
@@ -4105,10 +3941,6 @@ packages:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
- cacache@15.3.0:
- resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==}
- engines: {node: '>= 10'}
-
cacheable-lookup@7.0.0:
resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
engines: {node: '>=14.16'}
@@ -4212,6 +4044,10 @@ packages:
resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==}
engines: {node: '>=10'}
+ cli-color@2.0.4:
+ resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==}
+ engines: {node: '>=0.10'}
+
cli-cursor@5.0.0:
resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==}
engines: {node: '>=18'}
@@ -4394,9 +4230,6 @@ packages:
resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==}
engines: {node: '>=10.0.0'}
- create-require@1.1.1:
- resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
-
crelt@1.0.6:
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
@@ -4477,6 +4310,10 @@ packages:
resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
engines: {node: '>=12'}
+ d@1.0.2:
+ resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
+ engines: {node: '>=0.12'}
+
dargs@8.1.0:
resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==}
engines: {node: '>=12'}
@@ -4591,9 +4428,8 @@ packages:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
- diff@4.0.2:
- resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
- engines: {node: '>=0.3.1'}
+ difflib@0.2.4:
+ resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==}
dijkstrajs@1.0.3:
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
@@ -4652,29 +4488,25 @@ packages:
resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==}
engines: {node: '>=4'}
- drizzle-dbml-generator@0.10.0:
- resolution: {integrity: sha512-cMZq9E3U3RlmE0uBeXyc6oWJ0royOkC6HiTlc9LDeMe+W87poZTzKoNYUyAxZrs4Q1RQtob+cGKiefV4ZoI8HA==}
- peerDependencies:
- drizzle-orm: '>=0.36.0'
+ dreamopt@0.8.0:
+ resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==}
+ engines: {node: '>=0.4.0'}
- drizzle-kit@0.30.4:
- resolution: {integrity: sha512-B2oJN5UkvwwNHscPWXDG5KqAixu7AUzZ3qbe++KU9SsQ+cZWR4DXEPYcvWplyFAno0dhRJECNEhNxiDmFaPGyQ==}
+ drizzle-kit@0.21.4:
+ resolution: {integrity: sha512-Nxcc1ONJLRgbhmR+azxjNF9Ly9privNLEIgW53c92whb4xp8jZLH1kMCh/54ci1mTMuYxPdOukqLwJ8wRudNwA==}
hasBin: true
- drizzle-orm@0.39.1:
- resolution: {integrity: sha512-2bDHlzTY31IDmrYn8i+ZZrxK8IyBD4mPZ7JmZdVDQj2tpBZXs/gxB/1kK5pSvkjxPUMNOVsTnoGkSltgjuJwcA==}
+ drizzle-orm@0.30.10:
+ resolution: {integrity: sha512-IRy/QmMWw9lAQHpwbUh1b8fcn27S/a9zMIzqea1WNOxK9/4EB8gIo+FZWLiPXzl2n9ixGSv8BhsLZiOppWEwBw==}
peerDependencies:
'@aws-sdk/client-rds-data': '>=3'
- '@cloudflare/workers-types': '>=4'
- '@electric-sql/pglite': '>=0.2.0'
- '@libsql/client': '>=0.10.0'
- '@libsql/client-wasm': '>=0.10.0'
- '@neondatabase/serverless': '>=0.10.0'
+ '@cloudflare/workers-types': '>=3'
+ '@electric-sql/pglite': '>=0.1.1'
+ '@libsql/client': '*'
+ '@neondatabase/serverless': '>=0.1'
'@op-engineering/op-sqlite': '>=2'
'@opentelemetry/api': ^1.4.1
'@planetscale/database': '>=1'
- '@prisma/client': '*'
- '@tidbcloud/serverless': '*'
'@types/better-sqlite3': '*'
'@types/pg': '*'
'@types/react': 18.3.5
@@ -4683,13 +4515,12 @@ packages:
'@xata.io/client': '*'
better-sqlite3: '>=7'
bun-types: '*'
- expo-sqlite: '>=14.0.0'
+ expo-sqlite: '>=13.2.0'
knex: '*'
kysely: '*'
mysql2: '>=2'
pg: '>=8'
postgres: '>=3'
- prisma: '*'
react: '>=18'
sql.js: '>=1'
sqlite3: '>=5'
@@ -4702,8 +4533,6 @@ packages:
optional: true
'@libsql/client':
optional: true
- '@libsql/client-wasm':
- optional: true
'@neondatabase/serverless':
optional: true
'@op-engineering/op-sqlite':
@@ -4712,10 +4541,6 @@ packages:
optional: true
'@planetscale/database':
optional: true
- '@prisma/client':
- optional: true
- '@tidbcloud/serverless':
- optional: true
'@types/better-sqlite3':
optional: true
'@types/pg':
@@ -4744,8 +4569,6 @@ packages:
optional: true
postgres:
optional: true
- prisma:
- optional: true
react:
optional: true
sql.js:
@@ -4782,9 +4605,6 @@ packages:
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
- encoding@0.1.13:
- resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
-
end-of-stream@1.4.4:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
@@ -4800,13 +4620,14 @@ packages:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
engines: {node: '>=6'}
+ env-paths@3.0.0:
+ resolution: {integrity: sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
environment@1.1.0:
resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==}
engines: {node: '>=18'}
- err-code@2.0.3:
- resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
-
error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
@@ -4821,6 +4642,20 @@ packages:
es-module-lexer@1.5.4:
resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==}
+ es5-ext@0.10.64:
+ resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
+ engines: {node: '>=0.10'}
+
+ es6-iterator@2.0.3:
+ resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
+
+ es6-symbol@3.1.4:
+ resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
+ engines: {node: '>=0.12'}
+
+ es6-weak-map@2.0.3:
+ resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==}
+
esbuild-plugin-alias@0.2.1:
resolution: {integrity: sha512-jyfL/pwPqaFXyKnj8lP8iLk6Z0m099uXR45aSN8Av1XD4vhvQutxxPzgA2bTcAwQpa1zCXDcWOlhFgyP3GKqhQ==}
@@ -4868,6 +4703,10 @@ packages:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'}
+ esniff@2.0.1:
+ resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
+ engines: {node: '>=0.10'}
+
esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
engines: {node: '>=4.0'}
@@ -4886,6 +4725,9 @@ packages:
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+ event-emitter@0.3.5:
+ resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
+
event-target-shim@5.0.1:
resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==}
engines: {node: '>=6'}
@@ -4912,6 +4754,12 @@ packages:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
+ ext@1.7.0:
+ resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
+
+ extend@3.0.2:
+ resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+
fancy-ansi@0.1.3:
resolution: {integrity: sha512-tRQVTo5jjdSIiydqgzIIEZpKddzSsfGLsSVt6vWdjVm7fbvDTiQkyoPu6Z3dIPlAM4OZk0jP5jmTCX4G8WGgBw==}
@@ -4954,9 +4802,6 @@ packages:
fault@1.0.4:
resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==}
- file-uri-to-path@1.0.0:
- resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
-
fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'}
@@ -5027,11 +4872,6 @@ packages:
engines: {node: '>=10'}
deprecated: This package is no longer supported.
- gauge@4.0.4:
- resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- deprecated: This package is no longer supported.
-
generic-pool@3.9.0:
resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==}
engines: {node: '>= 4'}
@@ -5093,6 +4933,11 @@ packages:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
+ glob@8.1.0:
+ resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
+ engines: {node: '>=12'}
+ deprecated: Glob versions prior to v9 are no longer supported
+
global-directory@4.0.1:
resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==}
engines: {node: '>=18'}
@@ -5121,6 +4966,9 @@ packages:
h3@1.12.0:
resolution: {integrity: sha512-Zi/CcNeWBXDrFNlV0hUBJQR9F7a96RjMeAZweW/ZWkR9fuXrMcvKnSA63f/zZ9l0GgQOZDVHGvXivNN9PWOwhA==}
+ hanji@0.0.5:
+ resolution: {integrity: sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==}
+
has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
@@ -5159,6 +5007,9 @@ packages:
hastscript@6.0.0:
resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==}
+ heap@0.2.7:
+ resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==}
+
help-me@5.0.0:
resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==}
@@ -5195,10 +5046,6 @@ packages:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
- http-proxy-agent@4.0.1:
- resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==}
- engines: {node: '>= 6'}
-
http2-wrapper@2.2.1:
resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==}
engines: {node: '>=10.19.0'}
@@ -5211,9 +5058,6 @@ packages:
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
engines: {node: '>=16.17.0'}
- humanize-ms@1.2.1:
- resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
-
hyperdyperid@1.2.0:
resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==}
engines: {node: '>=10.18'}
@@ -5231,10 +5075,6 @@ packages:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
- iconv-lite@0.6.3:
- resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
- engines: {node: '>=0.10.0'}
-
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@@ -5253,10 +5093,6 @@ packages:
import-meta-resolve@4.1.0:
resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==}
- imurmurhash@0.1.4:
- resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
- engines: {node: '>=0.8.19'}
-
indent-string@4.0.0:
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
engines: {node: '>=8'}
@@ -5265,9 +5101,6 @@ packages:
resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==}
engines: {node: '>=12'}
- infer-owner@1.0.4:
- resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
-
inflation@2.1.0:
resolution: {integrity: sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==}
engines: {node: '>= 0.8.0'}
@@ -5306,10 +5139,6 @@ packages:
resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==}
engines: {node: '>=12.22.0'}
- ip-address@9.0.5:
- resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==}
- engines: {node: '>= 12'}
-
ip-regex@5.0.0:
resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -5382,9 +5211,6 @@ packages:
resolution: {integrity: sha512-4B4XA2HEIm/PY+OSpeMBXr8pGWBYbXuHgjMAqrwbLO3CPTCAd9ArEJzBUKGZtk9viY6+aSfadGnWyjY3ydYZkw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- is-lambda@1.0.1:
- resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
-
is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
@@ -5393,6 +5219,13 @@ packages:
resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
engines: {node: '>=8'}
+ is-plain-obj@4.1.0:
+ resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
+ engines: {node: '>=12'}
+
+ is-promise@2.2.2:
+ resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
+
is-stream@3.0.0:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -5419,16 +5252,10 @@ packages:
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
hasBin: true
- jose@5.9.6:
- resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==}
-
joycon@3.1.1:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
- js-base64@3.7.7:
- resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
-
js-beautify@1.15.1:
resolution: {integrity: sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==}
engines: {node: '>=14'}
@@ -5451,12 +5278,13 @@ packages:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
- jsbn@1.1.0:
- resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
-
json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+ json-diff@0.9.0:
+ resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==}
+ hasBin: true
+
json-parse-even-better-errors@2.3.1:
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
@@ -5533,10 +5361,6 @@ packages:
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
- kysely@0.27.5:
- resolution: {integrity: sha512-s7hZHcQeSNKpzCkHRm8yA+0JPLjncSWnjb+2TIElwS2JAqYr+Kv3Ess+9KFfJS0C1xcQ1i9NkNHpWwCYpHMWsA==}
- engines: {node: '>=14.0.0'}
-
leac@0.6.0:
resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==}
@@ -5684,6 +5508,9 @@ packages:
lodash.startcase@4.4.0:
resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
+ lodash.throttle@4.1.1:
+ resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
+
lodash.uniq@4.5.0:
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
@@ -5720,9 +5547,8 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
- lru-cache@6.0.0:
- resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
- engines: {node: '>=10'}
+ lru-queue@0.1.0:
+ resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==}
lucia@3.2.0:
resolution: {integrity: sha512-eXMxXwk6hqtjRTj4W/x3EnTUtAztLPm0p2N2TEBMDEbakDLXiYnDQ9z/qahjPdPdhPguQc+vwO0/88zIWxlpuw==}
@@ -5743,13 +5569,6 @@ packages:
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
engines: {node: '>=8'}
- make-error@1.3.6:
- resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
-
- make-fetch-happen@9.1.0:
- resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==}
- engines: {node: '>= 10'}
-
marked@7.0.4:
resolution: {integrity: sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ==}
engines: {node: '>= 16'}
@@ -5799,6 +5618,10 @@ packages:
resolution: {integrity: sha512-+6kz90/YQoZuHvg3rn1CGPMZfEMaU5xe7xIavZMNiom2RNesiI8S37p9O9n+PlIUnUgretjLdM6HnqpZYl3X2g==}
engines: {node: '>= 4.0.0'}
+ memoizee@0.4.17:
+ resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==}
+ engines: {node: '>=0.12'}
+
meow@12.1.1:
resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==}
engines: {node: '>=16.10'}
@@ -5925,6 +5748,10 @@ packages:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+ minimatch@5.1.6:
+ resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
+ engines: {node: '>=10'}
+
minimatch@7.4.6:
resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==}
engines: {node: '>=10'}
@@ -5940,26 +5767,6 @@ packages:
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
- minipass-collect@1.0.2:
- resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
- engines: {node: '>= 8'}
-
- minipass-fetch@1.4.1:
- resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==}
- engines: {node: '>=8'}
-
- minipass-flush@1.0.5:
- resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==}
- engines: {node: '>= 8'}
-
- minipass-pipeline@1.2.4:
- resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==}
- engines: {node: '>=8'}
-
- minipass-sized@1.0.3:
- resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==}
- engines: {node: '>=8'}
-
minipass@3.3.6:
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
engines: {node: '>=8'}
@@ -6015,9 +5822,10 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
- nanostores@0.11.3:
- resolution: {integrity: sha512-TUes3xKIX33re4QzdxwZ6tdbodjmn3tWXCEc1uokiEmo14sI1EaGYNs2k3bU2pyyGNmBqFGAVl6jAGWd06AVIg==}
- engines: {node: ^18.0.0 || >=20.0.0}
+ nanoid@3.3.8:
+ resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
@@ -6049,6 +5857,9 @@ packages:
react: '*'
react-dom: '*'
+ next-tick@1.1.0:
+ resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
+
next@15.0.1:
resolution: {integrity: sha512-PSkFkr/w7UnFWm+EP8y/QpHrJXMqpZzAXpergB/EqLPOh4SGPJXv1wj4mslr2hUZBAS9pX7/9YLIdxTv6fwytw==}
engines: {node: '>=18.18.0'}
@@ -6080,9 +5891,6 @@ packages:
node-addon-api@5.1.0:
resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==}
- node-addon-api@7.1.1:
- resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
-
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
@@ -6107,11 +5915,6 @@ packages:
resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==}
hasBin: true
- node-gyp@8.4.1:
- resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==}
- engines: {node: '>= 10.12.0'}
- hasBin: true
-
node-mocks-http@1.15.0:
resolution: {integrity: sha512-3orGBAxXrnwz3ixU8AZpa0x8srAvVSHvbWanAqd5F0zVCVA2QstxaVcTSarFcjz4+pFSnR1zm28MsV83s/BtmA==}
engines: {node: '>=14'}
@@ -6163,11 +5966,6 @@ packages:
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
deprecated: This package is no longer supported.
- npmlog@6.0.2:
- resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==}
- engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
- deprecated: This package is no longer supported.
-
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -6252,10 +6050,6 @@ packages:
resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- p-map@4.0.0:
- resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
- engines: {node: '>=10'}
-
p-try@2.2.0:
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
engines: {node: '>=6'}
@@ -6453,18 +6247,6 @@ packages:
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
engines: {node: '>= 0.6.0'}
- promise-inflight@1.0.1:
- resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
- peerDependencies:
- bluebird: '*'
- peerDependenciesMeta:
- bluebird:
- optional: true
-
- promise-retry@2.0.1:
- resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==}
- engines: {node: '>=10'}
-
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -6491,13 +6273,6 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
- pvtsutils@1.3.6:
- resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==}
-
- pvutils@1.1.3:
- resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==}
- engines: {node: '>=6.0.0'}
-
qrcode@1.5.4:
resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==}
engines: {node: '>=10.13.0'}
@@ -6566,12 +6341,6 @@ packages:
peerDependencies:
react: ^15.3.0 || 16 || 17 || 18
- react-day-picker@8.10.1:
- resolution: {integrity: sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==}
- peerDependencies:
- date-fns: ^2.28.0 || ^3.0.0
- react: ^16.8.0 || ^17.0.0 || ^18.0.0
-
react-debounce-input@3.3.0:
resolution: {integrity: sha512-VEqkvs8JvY/IIZvh71Z0TC+mdbxERvYF33RcebnodlsUZ8RSgyKe2VWaHXv4+/8aoOgXLxWrdsYs2hDhcwbUgA==}
peerDependencies:
@@ -6830,10 +6599,6 @@ packages:
resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==}
engines: {node: '>=4'}
- retry@0.12.0:
- resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
- engines: {node: '>= 4'}
-
reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -6855,9 +6620,6 @@ packages:
resolution: {integrity: sha512-cfmm3tqdnbuYw2FBmRTPBDaohYEbMJ3211T35o6eZdr4d7v69+ZeK1Av84Br7FLj2dlzyeZSbN6qTuXXE6dawQ==}
engines: {node: '>=14.0'}
- rou3@0.5.1:
- resolution: {integrity: sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==}
-
run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
@@ -6915,9 +6677,6 @@ packages:
set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
- set-cookie-parser@2.7.1:
- resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
-
set-function-length@1.2.2:
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
engines: {node: '>= 0.4'}
@@ -6971,6 +6730,9 @@ packages:
simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+ sisteransi@1.0.5:
+ resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
@@ -6991,18 +6753,6 @@ packages:
resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==}
engines: {node: '>=8.0.0'}
- smart-buffer@4.2.0:
- resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
- engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
-
- socks-proxy-agent@6.2.1:
- resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==}
- engines: {node: '>= 10'}
-
- socks@2.8.3:
- resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==}
- engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
-
sonic-boom@4.1.0:
resolution: {integrity: sha512-NGipjjRicyJJ03rPiZCJYjwlsuP2d1/5QUviozRXC7S3WdVWNK5e3Ojieb9CCyfhq2UC+3+SRd9nG3I2lPRvUw==}
@@ -7042,20 +6792,10 @@ packages:
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
- sprintf-js@1.1.3:
- resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
-
- sqlite3@5.1.7:
- resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==}
-
ssh2@1.15.0:
resolution: {integrity: sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==}
engines: {node: '>=10.16.0'}
- ssri@8.0.1:
- resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==}
- engines: {node: '>= 8'}
-
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
@@ -7262,6 +7002,10 @@ packages:
through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+ timers-ext@0.1.8:
+ resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==}
+ engines: {node: '>=0.12'}
+
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
@@ -7320,20 +7064,6 @@ packages:
ts-mixer@6.0.4:
resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==}
- ts-node@10.9.2:
- resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
- hasBin: true
- peerDependencies:
- '@swc/core': '>=1.2.50'
- '@swc/wasm': '>=1.2.50'
- '@types/node': '*'
- typescript: '>=2.7'
- peerDependenciesMeta:
- '@swc/core':
- optional: true
- '@swc/wasm':
- optional: true
-
ts-toolbelt@9.6.0:
resolution: {integrity: sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==}
@@ -7354,9 +7084,6 @@ packages:
tslib@2.6.3:
resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
- tslib@2.8.1:
- resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
-
tsx@4.16.2:
resolution: {integrity: sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==}
engines: {node: '>=18.0.0'}
@@ -7384,6 +7111,9 @@ packages:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
+ type@2.7.3:
+ resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
+
types-ramda@0.30.1:
resolution: {integrity: sha512-1HTsf5/QVRmLzcGfldPFvkVsAdi1db1BBKzi7iW3KBUlOICg/nKnFS+jGqDJS3YD8VsWbAh7JiHeBvbsw8RPxA==}
@@ -7392,11 +7122,6 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
- typescript@5.7.2:
- resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==}
- engines: {node: '>=14.17'}
- hasBin: true
-
ufo@1.5.4:
resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==}
@@ -7417,11 +7142,23 @@ packages:
resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==}
engines: {node: '>=18'}
- unique-filename@1.1.1:
- resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==}
+ unified@11.0.5:
+ resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
- unique-slug@2.0.2:
- resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==}
+ unist-util-is@6.0.0:
+ resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
+
+ unist-util-position@5.0.0:
+ resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
+
+ unist-util-stringify-position@4.0.0:
+ resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
+
+ unist-util-visit-parents@6.0.1:
+ resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
+
+ unist-util-visit@5.0.0:
+ resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
universal-github-app-jwt@1.1.2:
resolution: {integrity: sha512-t1iB2FmLFE+yyJY9+3wMx0ejB+MQpEVkH0gQv7dR6FZyltyq+ZZO0uDpbopxhrZ3SLEO4dCEkIujOMldEQ2iOA==}
@@ -7491,16 +7228,11 @@ packages:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
- v8-compile-cache-lib@3.0.1:
- resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
+ vfile-message@4.0.2:
+ resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
- valibot@1.0.0-beta.15:
- resolution: {integrity: sha512-BKy8XosZkDHWmYC+cJG74LBzP++Gfntwi33pP3D3RKztz2XV9jmFWnkOi21GoqARP8wAWARwhV6eTr1JcWzjGw==}
- peerDependencies:
- typescript: '>=5'
- peerDependenciesMeta:
- typescript:
- optional: true
+ vfile@6.0.3:
+ resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
victory-vendor@36.9.2:
resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==}
@@ -7629,6 +7361,9 @@ packages:
resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==}
engines: {node: '>=12'}
+ wordwrap@1.0.0:
+ resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
+
wrap-ansi@6.2.0:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
@@ -7711,10 +7446,6 @@ packages:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
- yn@3.1.1:
- resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
- engines: {node: '>=6'}
-
yocto-queue@1.1.1:
resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==}
engines: {node: '>=12.20'}
@@ -7740,8 +7471,8 @@ packages:
zod@3.23.8:
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
- zod@3.24.1:
- resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==}
+ zwitch@2.0.4:
+ resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
snapshots:
@@ -7860,12 +7591,6 @@ snapshots:
'@balena/dockerignore@1.0.2': {}
- '@better-auth/utils@0.2.3':
- dependencies:
- uncrypto: 0.1.3
-
- '@better-fetch/fetch@1.1.15': {}
-
'@biomejs/biome@1.9.4':
optionalDependencies:
'@biomejs/cli-darwin-arm64': 1.9.4
@@ -7973,11 +7698,11 @@ snapshots:
style-mod: 4.1.2
w3c-keyname: 2.2.8
- '@commitlint/cli@19.3.0(@types/node@18.19.42)(typescript@5.7.2)':
+ '@commitlint/cli@19.3.0(@types/node@18.19.42)(typescript@5.5.3)':
dependencies:
'@commitlint/format': 19.3.0
'@commitlint/lint': 19.2.2
- '@commitlint/load': 19.2.0(@types/node@18.19.42)(typescript@5.7.2)
+ '@commitlint/load': 19.2.0(@types/node@18.19.42)(typescript@5.5.3)
'@commitlint/read': 19.2.1
'@commitlint/types': 19.0.3
execa: 8.0.1
@@ -8024,15 +7749,15 @@ snapshots:
'@commitlint/rules': 19.0.3
'@commitlint/types': 19.0.3
- '@commitlint/load@19.2.0(@types/node@18.19.42)(typescript@5.7.2)':
+ '@commitlint/load@19.2.0(@types/node@18.19.42)(typescript@5.5.3)':
dependencies:
'@commitlint/config-validator': 19.0.3
'@commitlint/execute-rule': 19.0.0
'@commitlint/resolve-extends': 19.1.0
'@commitlint/types': 19.0.3
chalk: 5.3.0
- cosmiconfig: 9.0.0(typescript@5.7.2)
- cosmiconfig-typescript-loader: 5.0.0(@types/node@18.19.42)(cosmiconfig@9.0.0(typescript@5.7.2))(typescript@5.7.2)
+ cosmiconfig: 9.0.0(typescript@5.5.3)
+ cosmiconfig-typescript-loader: 5.0.0(@types/node@18.19.42)(cosmiconfig@9.0.0(typescript@5.5.3))(typescript@5.5.3)
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
lodash.uniq: 4.5.0
@@ -8084,11 +7809,6 @@ snapshots:
'@types/conventional-commits-parser': 5.0.0
chalk: 5.3.0
- '@cspotcode/source-map-support@0.8.1':
- dependencies:
- '@jridgewell/trace-mapping': 0.3.9
- optional: true
-
'@dokploy/trpc-openapi@0.0.4(@trpc/server@10.45.2)(zod@3.23.8)':
dependencies:
'@trpc/server': 10.45.2
@@ -8102,8 +7822,6 @@ snapshots:
transitivePeerDependencies:
- uWebSockets.js
- '@drizzle-team/brocli@0.10.2': {}
-
'@emnapi/core@0.45.0':
dependencies:
tslib: 2.6.3
@@ -8427,13 +8145,8 @@ snapshots:
'@floating-ui/utils@0.2.5': {}
- '@gar/promisify@1.1.3':
- optional: true
-
'@hapi/bourne@3.0.0': {}
- '@hexagon/base64@1.1.28': {}
-
'@hono/node-server@1.12.1': {}
'@hono/zod-validator@0.3.0(hono@4.5.8)(zod@3.23.8)':
@@ -8557,12 +8270,6 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
- '@jridgewell/trace-mapping@0.3.9':
- dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.5.0
- optional: true
-
'@jsonjoy.com/base64@1.1.2(tslib@2.6.3)':
dependencies:
tslib: 2.6.3
@@ -8583,8 +8290,6 @@ snapshots:
'@leichtgewicht/ip-codec@2.0.5': {}
- '@levischuck/tiny-cbor@0.2.11': {}
-
'@lezer/common@1.2.1': {}
'@lezer/highlight@1.2.0':
@@ -8611,12 +8316,12 @@ snapshots:
dependencies:
lucia: 3.2.0
- '@mapbox/node-pre-gyp@1.0.11(encoding@0.1.13)':
+ '@mapbox/node-pre-gyp@1.0.11':
dependencies:
detect-libc: 2.0.3
https-proxy-agent: 5.0.1
make-dir: 3.1.0
- node-fetch: 2.7.0(encoding@0.1.13)
+ node-fetch: 2.7.0
nopt: 5.0.0
npmlog: 5.0.1
rimraf: 3.0.2
@@ -8675,12 +8380,8 @@ snapshots:
'@next/swc-win32-x64-msvc@15.0.1':
optional: true
- '@noble/ciphers@0.6.0': {}
-
'@noble/hashes@1.5.0': {}
- '@noble/hashes@1.7.1': {}
-
'@node-rs/argon2-android-arm-eabi@1.7.0':
optional: true
@@ -8821,18 +8522,6 @@ snapshots:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
- '@npmcli/fs@1.1.1':
- dependencies:
- '@gar/promisify': 1.1.3
- semver: 7.6.3
- optional: true
-
- '@npmcli/move-file@1.1.2':
- dependencies:
- mkdirp: 1.0.4
- rimraf: 3.0.2
- optional: true
-
'@octokit/app@14.1.0':
dependencies:
'@octokit/auth-app': 6.1.1
@@ -9009,51 +8698,7 @@ snapshots:
'@one-ini/wasm@0.1.1': {}
- '@oslojs/asn1@1.0.0':
- dependencies:
- '@oslojs/binary': 1.0.0
-
- '@oslojs/binary@1.0.0': {}
-
- '@oslojs/crypto@1.0.1':
- dependencies:
- '@oslojs/asn1': 1.0.0
- '@oslojs/binary': 1.0.0
-
- '@oslojs/encoding@1.1.0': {}
-
- '@peculiar/asn1-android@2.3.15':
- dependencies:
- '@peculiar/asn1-schema': 2.3.15
- asn1js: 3.0.5
- tslib: 2.8.1
-
- '@peculiar/asn1-ecc@2.3.15':
- dependencies:
- '@peculiar/asn1-schema': 2.3.15
- '@peculiar/asn1-x509': 2.3.15
- asn1js: 3.0.5
- tslib: 2.8.1
-
- '@peculiar/asn1-rsa@2.3.15':
- dependencies:
- '@peculiar/asn1-schema': 2.3.15
- '@peculiar/asn1-x509': 2.3.15
- asn1js: 3.0.5
- tslib: 2.8.1
-
- '@peculiar/asn1-schema@2.3.15':
- dependencies:
- asn1js: 3.0.5
- pvtsutils: 1.3.6
- tslib: 2.8.1
-
- '@peculiar/asn1-x509@2.3.15':
- dependencies:
- '@peculiar/asn1-schema': 2.3.15
- asn1js: 3.0.5
- pvtsutils: 1.3.6
- tslib: 2.8.1
+ '@opentelemetry/api@1.9.0': {}
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -10048,18 +9693,6 @@ snapshots:
domhandler: 5.0.3
selderee: 0.11.0
- '@simplewebauthn/browser@13.1.0': {}
-
- '@simplewebauthn/server@13.1.1':
- dependencies:
- '@hexagon/base64': 1.1.28
- '@levischuck/tiny-cbor': 0.2.11
- '@peculiar/asn1-android': 2.3.15
- '@peculiar/asn1-ecc': 2.3.15
- '@peculiar/asn1-rsa': 2.3.15
- '@peculiar/asn1-schema': 2.3.15
- '@peculiar/asn1-x509': 2.3.15
-
'@sinclair/typebox@0.27.8': {}
'@sindresorhus/is@5.6.0': {}
@@ -10441,9 +10074,6 @@ snapshots:
'@tanstack/table-core@8.19.3': {}
- '@tootallnate/once@1.1.2':
- optional: true
-
'@trpc/client@10.45.2(@trpc/server@10.45.2)':
dependencies:
'@trpc/server': 10.45.2
@@ -10468,18 +10098,6 @@ snapshots:
'@trpc/server@10.45.2': {}
- '@tsconfig/node10@1.0.11':
- optional: true
-
- '@tsconfig/node12@1.0.11':
- optional: true
-
- '@tsconfig/node14@1.0.3':
- optional: true
-
- '@tsconfig/node16@1.0.4':
- optional: true
-
'@tybys/wasm-util@0.8.3':
dependencies:
tslib: 2.6.3
@@ -10844,11 +10462,6 @@ snapshots:
dependencies:
'@xterm/xterm': 5.5.0
- '@xterm/addon-clipboard@0.1.0(@xterm/xterm@5.5.0)':
- dependencies:
- '@xterm/xterm': 5.5.0
- js-base64: 3.7.7
-
'@xterm/xterm@5.5.0': {}
'@xtuc/ieee754@1.2.0': {}
@@ -10891,11 +10504,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- agentkeepalive@4.6.0:
- dependencies:
- humanize-ms: 1.2.1
- optional: true
-
aggregate-error@3.1.0:
dependencies:
clean-stack: 2.2.0
@@ -10986,15 +10594,6 @@ snapshots:
delegates: 1.0.0
readable-stream: 3.6.2
- are-we-there-yet@3.0.1:
- dependencies:
- delegates: 1.0.0
- readable-stream: 3.6.2
- optional: true
-
- arg@4.1.3:
- optional: true
-
arg@5.0.2: {}
argparse@1.0.10:
@@ -11015,12 +10614,6 @@ snapshots:
dependencies:
safer-buffer: 2.1.2
- asn1js@3.0.5:
- dependencies:
- pvtsutils: 1.3.6
- pvutils: 1.1.3
- tslib: 2.8.1
-
assertion-error@1.1.0: {}
async-await-queue@2.1.4: {}
@@ -11061,9 +10654,9 @@ snapshots:
dependencies:
tweetnacl: 0.14.5
- bcrypt@5.1.1(encoding@0.1.13):
+ bcrypt@5.1.1:
dependencies:
- '@mapbox/node-pre-gyp': 1.0.11(encoding@0.1.13)
+ '@mapbox/node-pre-gyp': 1.0.11
node-addon-api: 5.1.0
transitivePeerDependencies:
- encoding
@@ -11071,38 +10664,8 @@ snapshots:
before-after-hook@2.2.3: {}
- better-auth@1.2.0(typescript@5.5.3):
- dependencies:
- '@better-auth/utils': 0.2.3
- '@better-fetch/fetch': 1.1.15
- '@noble/ciphers': 0.6.0
- '@noble/hashes': 1.7.1
- '@simplewebauthn/browser': 13.1.0
- '@simplewebauthn/server': 13.1.1
- better-call: 1.0.3
- defu: 6.1.4
- jose: 5.9.6
- kysely: 0.27.5
- nanostores: 0.11.3
- valibot: 1.0.0-beta.15(typescript@5.5.3)
- zod: 3.24.1
- transitivePeerDependencies:
- - typescript
-
- better-call@1.0.3:
- dependencies:
- '@better-fetch/fetch': 1.1.15
- rou3: 0.5.1
- set-cookie-parser: 2.7.1
- uncrypto: 0.1.3
-
binary-extensions@2.3.0: {}
- bindings@1.5.0:
- dependencies:
- file-uri-to-path: 1.0.0
- optional: true
-
bl@4.1.0:
dependencies:
buffer: 5.7.1
@@ -11189,30 +10752,6 @@ snapshots:
cac@6.7.14: {}
- cacache@15.3.0:
- dependencies:
- '@npmcli/fs': 1.1.1
- '@npmcli/move-file': 1.1.2
- chownr: 2.0.0
- fs-minipass: 2.1.0
- glob: 7.2.3
- infer-owner: 1.0.4
- lru-cache: 6.0.0
- minipass: 3.3.6
- minipass-collect: 1.0.2
- minipass-flush: 1.0.5
- minipass-pipeline: 1.2.4
- mkdirp: 1.0.4
- p-map: 4.0.0
- promise-inflight: 1.0.1
- rimraf: 3.0.2
- ssri: 8.0.1
- tar: 6.2.1
- unique-filename: 1.1.1
- transitivePeerDependencies:
- - bluebird
- optional: true
-
cacheable-lookup@7.0.0: {}
cacheable-request@10.2.14:
@@ -11313,6 +10852,14 @@ snapshots:
cli-boxes@3.0.0: {}
+ cli-color@2.0.4:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ es6-iterator: 2.0.3
+ memoizee: 0.4.17
+ timers-ext: 0.1.8
+
cli-cursor@5.0.0:
dependencies:
restore-cursor: 5.1.0
@@ -11479,21 +11026,21 @@ snapshots:
core-js@3.39.0: {}
- cosmiconfig-typescript-loader@5.0.0(@types/node@18.19.42)(cosmiconfig@9.0.0(typescript@5.7.2))(typescript@5.7.2):
+ cosmiconfig-typescript-loader@5.0.0(@types/node@18.19.42)(cosmiconfig@9.0.0(typescript@5.5.3))(typescript@5.5.3):
dependencies:
'@types/node': 18.19.42
- cosmiconfig: 9.0.0(typescript@5.7.2)
+ cosmiconfig: 9.0.0(typescript@5.5.3)
jiti: 1.21.6
- typescript: 5.7.2
+ typescript: 5.5.3
- cosmiconfig@9.0.0(typescript@5.7.2):
+ cosmiconfig@9.0.0(typescript@5.5.3):
dependencies:
env-paths: 2.2.1
import-fresh: 3.3.0
js-yaml: 4.1.0
parse-json: 5.2.0
optionalDependencies:
- typescript: 5.7.2
+ typescript: 5.5.3
cpu-features@0.0.10:
dependencies:
@@ -11501,9 +11048,6 @@ snapshots:
nan: 2.20.0
optional: true
- create-require@1.1.1:
- optional: true
-
crelt@1.0.6: {}
cron-parser@4.9.0:
@@ -11573,6 +11117,11 @@ snapshots:
d3-timer@3.0.1: {}
+ d@1.0.2:
+ dependencies:
+ es5-ext: 0.10.64
+ type: 2.7.3
+
dargs@8.1.0: {}
date-fns@3.6.0: {}
@@ -11647,8 +11196,9 @@ snapshots:
diff-sequences@29.6.3: {}
- diff@4.0.2:
- optional: true
+ difflib@0.2.4:
+ dependencies:
+ heap: 0.2.7
dijkstrajs@1.0.3: {}
@@ -11716,31 +11266,34 @@ snapshots:
drange@1.1.1: {}
- drizzle-dbml-generator@0.10.0(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7)):
+ dreamopt@0.8.0:
dependencies:
- drizzle-orm: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7)
+ wordwrap: 1.0.0
- drizzle-kit@0.30.4:
+ drizzle-kit@0.21.4:
dependencies:
- '@drizzle-team/brocli': 0.10.2
'@esbuild-kit/esm-loader': 2.6.5
+ commander: 9.5.0
+ env-paths: 3.0.0
esbuild: 0.19.12
esbuild-register: 3.6.0(esbuild@0.19.12)
+ glob: 8.1.0
+ hanji: 0.0.5
+ json-diff: 0.9.0
+ zod: 3.23.8
transitivePeerDependencies:
- supports-color
- drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7):
+ drizzle-orm@0.30.10(@opentelemetry/api@1.9.0)(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0):
optionalDependencies:
'@opentelemetry/api': 1.9.0
'@types/react': 18.3.5
- kysely: 0.27.5
postgres: 3.4.4
react: 18.2.0
- sqlite3: 5.1.7
- drizzle-zod@0.5.1(drizzle-orm@0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7))(zod@3.23.8):
+ drizzle-zod@0.5.1(drizzle-orm@0.30.10(@opentelemetry/api@1.9.0)(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0))(zod@3.23.8):
dependencies:
- drizzle-orm: 0.39.1(@types/react@18.3.5)(kysely@0.27.5)(postgres@3.4.4)(react@18.2.0)(sqlite3@5.1.7)
+ drizzle-orm: 0.30.10(@opentelemetry/api@1.9.0)(@types/react@18.3.5)(postgres@3.4.4)(react@18.2.0)
zod: 3.23.8
eastasianwidth@0.2.0: {}
@@ -11764,11 +11317,6 @@ snapshots:
emoji-regex@9.2.2: {}
- encoding@0.1.13:
- dependencies:
- iconv-lite: 0.6.3
- optional: true
-
end-of-stream@1.4.4:
dependencies:
once: 1.4.0
@@ -11782,10 +11330,9 @@ snapshots:
env-paths@2.2.1: {}
- environment@1.1.0: {}
+ env-paths@3.0.0: {}
- err-code@2.0.3:
- optional: true
+ environment@1.1.0: {}
error-ex@1.3.2:
dependencies:
@@ -11799,6 +11346,31 @@ snapshots:
es-module-lexer@1.5.4: {}
+ es5-ext@0.10.64:
+ dependencies:
+ es6-iterator: 2.0.3
+ es6-symbol: 3.1.4
+ esniff: 2.0.1
+ next-tick: 1.1.0
+
+ es6-iterator@2.0.3:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ es6-symbol: 3.1.4
+
+ es6-symbol@3.1.4:
+ dependencies:
+ d: 1.0.2
+ ext: 1.7.0
+
+ es6-weak-map@2.0.3:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ es6-iterator: 2.0.3
+ es6-symbol: 3.1.4
+
esbuild-plugin-alias@0.2.1: {}
esbuild-register@3.6.0(esbuild@0.19.12):
@@ -11924,6 +11496,13 @@ snapshots:
esrecurse: 4.3.0
estraverse: 4.3.0
+ esniff@2.0.1:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ event-emitter: 0.3.5
+ type: 2.7.3
+
esrecurse@4.3.0:
dependencies:
estraverse: 5.3.0
@@ -11938,6 +11517,11 @@ snapshots:
dependencies:
'@types/estree': 1.0.5
+ event-emitter@0.3.5:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+
event-target-shim@5.0.1: {}
eventemitter3@4.0.7: {}
@@ -11963,6 +11547,12 @@ snapshots:
expand-template@2.0.3:
optional: true
+ ext@1.7.0:
+ dependencies:
+ type: 2.7.3
+
+ extend@3.0.2: {}
+
fancy-ansi@0.1.3:
dependencies:
escape-html: 1.0.3
@@ -12001,9 +11591,6 @@ snapshots:
dependencies:
format: 0.2.2
- file-uri-to-path@1.0.0:
- optional: true
-
fill-range@7.1.1:
dependencies:
to-regex-range: 5.0.1
@@ -12068,18 +11655,6 @@ snapshots:
strip-ansi: 6.0.1
wide-align: 1.1.5
- gauge@4.0.4:
- dependencies:
- aproba: 2.0.0
- color-support: 1.1.3
- console-control-strings: 1.1.0
- has-unicode: 2.0.1
- signal-exit: 3.0.7
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wide-align: 1.1.5
- optional: true
-
generic-pool@3.9.0: {}
get-caller-file@2.0.5: {}
@@ -12143,6 +11718,14 @@ snapshots:
once: 1.4.0
path-is-absolute: 1.0.1
+ glob@8.1.0:
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 5.1.6
+ once: 1.4.0
+
global-directory@4.0.1:
dependencies:
ini: 4.1.1
@@ -12202,6 +11785,11 @@ snapshots:
transitivePeerDependencies:
- uWebSockets.js
+ hanji@0.0.5:
+ dependencies:
+ lodash.throttle: 4.1.1
+ sisteransi: 1.0.5
+
has-flag@3.0.0: {}
has-flag@4.0.0: {}
@@ -12254,6 +11842,8 @@ snapshots:
property-information: 5.6.0
space-separated-tokens: 1.1.5
+ heap@0.2.7: {}
+
help-me@5.0.0: {}
hi-base32@0.5.1: {}
@@ -12297,15 +11887,6 @@ snapshots:
statuses: 2.0.1
toidentifier: 1.0.1
- http-proxy-agent@4.0.1:
- dependencies:
- '@tootallnate/once': 1.1.2
- agent-base: 6.0.2
- debug: 4.3.7
- transitivePeerDependencies:
- - supports-color
- optional: true
-
http2-wrapper@2.2.1:
dependencies:
quick-lru: 5.1.1
@@ -12320,11 +11901,6 @@ snapshots:
human-signals@5.0.0: {}
- humanize-ms@1.2.1:
- dependencies:
- ms: 2.1.3
- optional: true
-
hyperdyperid@1.2.0: {}
hyphenate-style-name@1.1.0: {}
@@ -12339,11 +11915,6 @@ snapshots:
dependencies:
safer-buffer: 2.1.2
- iconv-lite@0.6.3:
- dependencies:
- safer-buffer: 2.1.2
- optional: true
-
ieee754@1.2.1: {}
ignore@5.3.1: {}
@@ -12357,16 +11928,10 @@ snapshots:
import-meta-resolve@4.1.0: {}
- imurmurhash@0.1.4:
- optional: true
-
indent-string@4.0.0: {}
indent-string@5.0.0: {}
- infer-owner@1.0.4:
- optional: true
-
inflation@2.1.0: {}
inflight@1.0.6:
@@ -12407,12 +11972,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- ip-address@9.0.5:
- dependencies:
- jsbn: 1.1.0
- sprintf-js: 1.1.3
- optional: true
-
ip-regex@5.0.0: {}
iron-webcrypto@1.2.1: {}
@@ -12472,13 +12031,14 @@ snapshots:
dependencies:
ip-regex: 5.0.0
- is-lambda@1.0.1:
- optional: true
-
is-number@7.0.0: {}
is-obj@2.0.0: {}
+ is-plain-obj@4.1.0: {}
+
+ is-promise@2.2.2: {}
+
is-stream@3.0.0: {}
is-text-path@2.0.0:
@@ -12503,12 +12063,8 @@ snapshots:
jiti@1.21.6: {}
- jose@5.9.6: {}
-
joycon@3.1.1: {}
- js-base64@3.7.7: {}
-
js-beautify@1.15.1:
dependencies:
config-chain: 1.1.13
@@ -12529,11 +12085,14 @@ snapshots:
dependencies:
argparse: 2.0.1
- jsbn@1.1.0:
- optional: true
-
json-buffer@3.0.1: {}
+ json-diff@0.9.0:
+ dependencies:
+ cli-color: 2.0.4
+ difflib: 0.2.4
+ dreamopt: 0.8.0
+
json-parse-even-better-errors@2.3.1: {}
json-schema-traverse@0.4.1: {}
@@ -12670,8 +12229,6 @@ snapshots:
dependencies:
json-buffer: 3.0.1
- kysely@0.27.5: {}
-
leac@0.6.0: {}
lefthook-darwin-arm64@1.8.4:
@@ -12798,6 +12355,8 @@ snapshots:
lodash.startcase@4.4.0: {}
+ lodash.throttle@4.1.1: {}
+
lodash.uniq@4.5.0: {}
lodash.upperfirst@4.3.1: {}
@@ -12833,10 +12392,9 @@ snapshots:
lru-cache@10.4.3: {}
- lru-cache@6.0.0:
+ lru-queue@0.1.0:
dependencies:
- yallist: 4.0.0
- optional: true
+ es5-ext: 0.10.64
lucia@3.2.0:
dependencies:
@@ -12856,32 +12414,6 @@ snapshots:
dependencies:
semver: 6.3.1
- make-error@1.3.6:
- optional: true
-
- make-fetch-happen@9.1.0:
- dependencies:
- agentkeepalive: 4.6.0
- cacache: 15.3.0
- http-cache-semantics: 4.1.1
- http-proxy-agent: 4.0.1
- https-proxy-agent: 5.0.1
- is-lambda: 1.0.1
- lru-cache: 6.0.0
- minipass: 3.3.6
- minipass-collect: 1.0.2
- minipass-fetch: 1.4.1
- minipass-flush: 1.0.5
- minipass-pipeline: 1.2.4
- negotiator: 0.6.3
- promise-retry: 2.0.1
- socks-proxy-agent: 6.2.1
- ssri: 8.0.1
- transitivePeerDependencies:
- - bluebird
- - supports-color
- optional: true
-
marked@7.0.4: {}
md-to-react-email@5.0.2(react@18.2.0):
@@ -12997,6 +12529,17 @@ snapshots:
tree-dump: 1.0.2(tslib@2.6.3)
tslib: 2.6.3
+ memoizee@0.4.17:
+ dependencies:
+ d: 1.0.2
+ es5-ext: 0.10.64
+ es6-weak-map: 2.0.3
+ event-emitter: 0.3.5
+ is-promise: 2.2.2
+ lru-queue: 0.1.0
+ next-tick: 1.1.0
+ timers-ext: 0.1.8
+
meow@12.1.1: {}
merge-descriptors@1.0.3: {}
@@ -13171,6 +12714,10 @@ snapshots:
dependencies:
brace-expansion: 1.1.11
+ minimatch@5.1.6:
+ dependencies:
+ brace-expansion: 2.0.1
+
minimatch@7.4.6:
dependencies:
brace-expansion: 2.0.1
@@ -13185,35 +12732,6 @@ snapshots:
minimist@1.2.8: {}
- minipass-collect@1.0.2:
- dependencies:
- minipass: 3.3.6
- optional: true
-
- minipass-fetch@1.4.1:
- dependencies:
- minipass: 3.3.6
- minipass-sized: 1.0.3
- minizlib: 2.1.2
- optionalDependencies:
- encoding: 0.1.13
- optional: true
-
- minipass-flush@1.0.5:
- dependencies:
- minipass: 3.3.6
- optional: true
-
- minipass-pipeline@1.2.4:
- dependencies:
- minipass: 3.3.6
- optional: true
-
- minipass-sized@1.0.3:
- dependencies:
- minipass: 3.3.6
- optional: true
-
minipass@3.3.6:
dependencies:
yallist: 4.0.0
@@ -13270,7 +12788,7 @@ snapshots:
nanoid@3.3.7: {}
- nanostores@0.11.3: {}
+ nanoid@3.3.8: {}
napi-build-utils@1.0.2:
optional: true
@@ -13299,7 +12817,9 @@ snapshots:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
- next@15.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
+ next-tick@1.1.0: {}
+
+ next@15.0.1(@opentelemetry/api@1.9.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@next/env': 15.0.1
'@swc/counter': 0.1.3
@@ -13327,16 +12847,13 @@ snapshots:
node-abi@3.68.0:
dependencies:
- semver: 7.6.3
+ semver: 7.6.2
optional: true
node-abort-controller@3.1.1: {}
node-addon-api@5.1.0: {}
- node-addon-api@7.1.1:
- optional: true
-
node-domexception@1.0.0: {}
node-fetch-commonjs@3.3.2:
@@ -13346,34 +12863,15 @@ snapshots:
node-fetch-native@1.6.4: {}
- node-fetch@2.7.0(encoding@0.1.13):
+ node-fetch@2.7.0:
dependencies:
whatwg-url: 5.0.0
- optionalDependencies:
- encoding: 0.1.13
node-gyp-build-optional-packages@5.2.2:
dependencies:
detect-libc: 2.0.3
optional: true
- node-gyp@8.4.1:
- dependencies:
- env-paths: 2.2.1
- glob: 7.2.3
- graceful-fs: 4.2.11
- make-fetch-happen: 9.1.0
- nopt: 5.0.0
- npmlog: 6.0.2
- rimraf: 3.0.2
- semver: 7.6.3
- tar: 6.2.1
- which: 2.0.2
- transitivePeerDependencies:
- - bluebird
- - supports-color
- optional: true
-
node-mocks-http@1.15.0:
dependencies:
'@types/express': 4.17.21
@@ -13430,14 +12928,6 @@ snapshots:
gauge: 3.0.2
set-blocking: 2.0.0
- npmlog@6.0.2:
- dependencies:
- are-we-there-yet: 3.0.1
- console-control-strings: 1.1.0
- gauge: 4.0.4
- set-blocking: 2.0.0
- optional: true
-
object-assign@4.1.1: {}
object-hash@3.0.0: {}
@@ -13522,11 +13012,6 @@ snapshots:
dependencies:
p-limit: 4.0.0
- p-map@4.0.0:
- dependencies:
- aggregate-error: 3.1.0
- optional: true
-
p-try@2.2.0: {}
package-json-from-dist@1.0.0: {}
@@ -13669,13 +13154,12 @@ snapshots:
camelcase-css: 2.0.1
postcss: 8.4.40
- postcss-load-config@4.0.2(postcss@8.4.40)(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.3)):
+ postcss-load-config@4.0.2(postcss@8.4.40):
dependencies:
lilconfig: 3.1.2
yaml: 2.4.5
optionalDependencies:
postcss: 8.4.40
- ts-node: 10.9.2(@types/node@18.19.42)(typescript@5.5.3)
postcss-nested@6.2.0(postcss@8.4.40):
dependencies:
@@ -13738,15 +13222,6 @@ snapshots:
process@0.11.10: {}
- promise-inflight@1.0.1:
- optional: true
-
- promise-retry@2.0.1:
- dependencies:
- err-code: 2.0.3
- retry: 0.12.0
- optional: true
-
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
@@ -13777,12 +13252,6 @@ snapshots:
punycode@2.3.1: {}
- pvtsutils@1.3.6:
- dependencies:
- tslib: 2.8.1
-
- pvutils@1.1.3: {}
-
qrcode@1.5.4:
dependencies:
dijkstrajs: 1.0.3
@@ -13850,11 +13319,6 @@ snapshots:
prop-types: 15.8.1
react: 18.2.0
- react-day-picker@8.10.1(date-fns@3.6.0)(react@18.2.0):
- dependencies:
- date-fns: 3.6.0
- react: 18.2.0
-
react-debounce-input@3.3.0(react@18.2.0):
dependencies:
lodash.debounce: 4.0.8
@@ -14144,9 +13608,6 @@ snapshots:
ret@0.2.2: {}
- retry@0.12.0:
- optional: true
-
reusify@1.0.4: {}
rfdc@1.4.1: {}
@@ -14179,8 +13640,6 @@ snapshots:
rotating-file-stream@3.2.3: {}
- rou3@0.5.1: {}
-
run-parallel@1.2.0:
dependencies:
queue-microtask: 1.2.3
@@ -14233,8 +13692,6 @@ snapshots:
set-blocking@2.0.0: {}
- set-cookie-parser@2.7.1: {}
-
set-function-length@1.2.2:
dependencies:
define-data-property: 1.1.4
@@ -14316,6 +13773,8 @@ snapshots:
is-arrayish: 0.3.2
optional: true
+ sisteransi@1.0.5: {}
+
slash@3.0.0: {}
slash@5.1.0: {}
@@ -14332,24 +13791,6 @@ snapshots:
slugify@1.6.6: {}
- smart-buffer@4.2.0:
- optional: true
-
- socks-proxy-agent@6.2.1:
- dependencies:
- agent-base: 6.0.2
- debug: 4.3.7
- socks: 2.8.3
- transitivePeerDependencies:
- - supports-color
- optional: true
-
- socks@2.8.3:
- dependencies:
- ip-address: 9.0.5
- smart-buffer: 4.2.0
- optional: true
-
sonic-boom@4.1.0:
dependencies:
atomic-sleep: 1.0.0
@@ -14380,22 +13821,6 @@ snapshots:
sprintf-js@1.0.3: {}
- sprintf-js@1.1.3:
- optional: true
-
- sqlite3@5.1.7:
- dependencies:
- bindings: 1.5.0
- node-addon-api: 7.1.1
- prebuild-install: 7.1.2
- tar: 6.2.1
- optionalDependencies:
- node-gyp: 8.4.1
- transitivePeerDependencies:
- - bluebird
- - supports-color
- optional: true
-
ssh2@1.15.0:
dependencies:
asn1: 0.2.6
@@ -14404,11 +13829,6 @@ snapshots:
cpu-features: 0.0.10
nan: 2.20.0
- ssri@8.0.1:
- dependencies:
- minipass: 3.3.6
- optional: true
-
stackback@0.0.2: {}
standard-as-callback@2.1.0: {}
@@ -14580,11 +14000,11 @@ snapshots:
tailwind-merge@2.4.0: {}
- tailwindcss-animate@1.0.7(tailwindcss@3.4.7(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.3))):
+ tailwindcss-animate@1.0.7(tailwindcss@3.4.7):
dependencies:
- tailwindcss: 3.4.7(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.3))
+ tailwindcss: 3.4.7
- tailwindcss@3.4.7(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.3)):
+ tailwindcss@3.4.7:
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -14603,7 +14023,7 @@ snapshots:
postcss: 8.4.40
postcss-import: 15.1.0(postcss@8.4.40)
postcss-js: 4.0.1(postcss@8.4.40)
- postcss-load-config: 4.0.2(postcss@8.4.40)(ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.3))
+ postcss-load-config: 4.0.2(postcss@8.4.40)
postcss-nested: 6.2.0(postcss@8.4.40)
postcss-selector-parser: 6.1.1
resolve: 1.22.8
@@ -14685,6 +14105,11 @@ snapshots:
through@2.3.8: {}
+ timers-ext@0.1.8:
+ dependencies:
+ es5-ext: 0.10.64
+ next-tick: 1.1.0
+
tiny-invariant@1.3.3: {}
tiny-warning@1.0.3: {}
@@ -14733,25 +14158,6 @@ snapshots:
ts-mixer@6.0.4: {}
- ts-node@10.9.2(@types/node@18.19.42)(typescript@5.5.3):
- dependencies:
- '@cspotcode/source-map-support': 0.8.1
- '@tsconfig/node10': 1.0.11
- '@tsconfig/node12': 1.0.11
- '@tsconfig/node14': 1.0.3
- '@tsconfig/node16': 1.0.4
- '@types/node': 18.19.42
- acorn: 8.12.1
- acorn-walk: 8.3.3
- arg: 4.1.3
- create-require: 1.1.1
- diff: 4.0.2
- make-error: 1.3.6
- typescript: 5.5.3
- v8-compile-cache-lib: 3.0.1
- yn: 3.1.1
- optional: true
-
ts-toolbelt@9.6.0: {}
tsc-alias@1.8.10:
@@ -14769,8 +14175,6 @@ snapshots:
tslib@2.6.3: {}
- tslib@2.8.1: {}
-
tsx@4.16.2:
dependencies:
esbuild: 0.21.5
@@ -14796,14 +14200,14 @@ snapshots:
media-typer: 0.3.0
mime-types: 2.1.35
+ type@2.7.3: {}
+
types-ramda@0.30.1:
dependencies:
ts-toolbelt: 9.6.0
typescript@5.5.3: {}
- typescript@5.7.2: {}
-
ufo@1.5.4: {}
uncrypto@0.1.3: {}
@@ -14822,15 +14226,38 @@ snapshots:
unicorn-magic@0.1.0: {}
- unique-filename@1.1.1:
+ unified@11.0.5:
dependencies:
- unique-slug: 2.0.2
- optional: true
+ '@types/unist': 3.0.3
+ bail: 2.0.2
+ devlop: 1.1.0
+ extend: 3.0.2
+ is-plain-obj: 4.1.0
+ trough: 2.2.0
+ vfile: 6.0.3
- unique-slug@2.0.2:
+ unist-util-is@6.0.0:
dependencies:
- imurmurhash: 0.1.4
- optional: true
+ '@types/unist': 3.0.3
+
+ unist-util-position@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-stringify-position@4.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+
+ unist-util-visit-parents@6.0.1:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.0
+
+ unist-util-visit@5.0.0:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-is: 6.0.0
+ unist-util-visit-parents: 6.0.1
universal-github-app-jwt@1.1.2:
dependencies:
@@ -14891,12 +14318,15 @@ snapshots:
uuid@9.0.1: {}
- v8-compile-cache-lib@3.0.1:
- optional: true
+ vfile-message@4.0.2:
+ dependencies:
+ '@types/unist': 3.0.3
+ unist-util-stringify-position: 4.0.0
- valibot@1.0.0-beta.15(typescript@5.5.3):
- optionalDependencies:
- typescript: 5.5.3
+ vfile@6.0.3:
+ dependencies:
+ '@types/unist': 3.0.3
+ vfile-message: 4.0.2
victory-vendor@36.9.2:
dependencies:
@@ -15059,6 +14489,8 @@ snapshots:
dependencies:
string-width: 5.1.2
+ wordwrap@1.0.0: {}
+
wrap-ansi@6.2.0:
dependencies:
ansi-styles: 4.3.0
@@ -15140,9 +14572,6 @@ snapshots:
y18n: 5.0.8
yargs-parser: 21.1.1
- yn@3.1.1:
- optional: true
-
yocto-queue@1.1.1: {}
zenscroll@4.0.2: {}
@@ -15161,4 +14590,4 @@ snapshots:
zod@3.23.8: {}
- zod@3.24.1: {}
+ zwitch@2.0.4: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 2cb911db..3ca0730a 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,7 +1,6 @@
packages:
- "apps/dokploy"
- "apps/api"
- - "apps/monitoring"
- "apps/schedules"
- "apps/models"
- "packages/server"