mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01e5cf0852 | ||
|
|
8faa6ae1cf | ||
|
|
76ed1107c2 | ||
|
|
cff5049096 | ||
|
|
cb5ca100a6 | ||
|
|
03d1e974dd | ||
|
|
b609d72d1c | ||
|
|
d7071fba60 | ||
|
|
76585991ec | ||
|
|
da6efcf733 | ||
|
|
64b0770cfb | ||
|
|
1ec83a3236 | ||
|
|
0a123a652b | ||
|
|
f8721d3e04 | ||
|
|
a6c7c3b031 |
@@ -17,10 +17,10 @@ See the License for the specific language governing permissions and limitations
|
|||||||
|
|
||||||
## Additional Terms for Specific Features
|
## Additional Terms for Specific Features
|
||||||
|
|
||||||
The following additional terms apply to the multi-node support and Docker Compose file support features of Dokploy. In the event of a conflict, these provisions shall take precedence over those in the Apache License:
|
The following additional terms apply to the multi-node support, Docker Compose file and Multi Server features of Dokploy. In the event of a conflict, these provisions shall take precedence over those in the Apache License:
|
||||||
|
|
||||||
- **Self-Hosted Version Free**: All features of Dokploy, including multi-node support and Docker Compose file support, will always be free to use in the self-hosted version.
|
- **Self-Hosted Version Free**: All features of Dokploy, including multi-node support, Docker Compose file support and Multi Server, will always be free to use in the self-hosted version.
|
||||||
- **Restriction on Resale**: The multi-node support and Docker Compose file support features cannot be sold or offered as a service by any party other than the copyright holder without prior written consent.
|
- **Restriction on Resale**: The multi-node support, Docker Compose file support and Multi Server features cannot be sold or offered as a service by any party other than the copyright holder without prior written consent.
|
||||||
- **Modification Distribution**: Any modifications to the multi-node support and Docker Compose file support features must be distributed freely and cannot be sold or offered as a service.
|
- **Modification Distribution**: Any modifications to the multi-node support, Docker Compose file support and Multi Server features must be distributed freely and cannot be sold or offered as a service.
|
||||||
|
|
||||||
For further inquiries or permissions, please contact us directly.
|
For further inquiries or permissions, please contact us directly.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dokploy",
|
"name": "dokploy",
|
||||||
"version": "v0.10.1",
|
"version": "v0.10.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"build-server": "tsx esbuild.config.ts",
|
"build-server": "tsx esbuild.config.ts",
|
||||||
"build-next": "next build",
|
"build-next": "next build",
|
||||||
"setup": "tsx -r dotenv/config setup.ts && sleep 5 && pnpm run migration:run",
|
"setup": "tsx -r dotenv/config setup.ts && sleep 5 && pnpm run migration:run",
|
||||||
"reset-password": "node dist/reset-password.mjs",
|
"reset-password": "node -r dotenv/config dist/reset-password.mjs",
|
||||||
"dev": "tsx -r dotenv/config ./server/server.ts --project tsconfig.server.json ",
|
"dev": "tsx -r dotenv/config ./server/server.ts --project tsconfig.server.json ",
|
||||||
"studio": "drizzle-kit studio --config ./server/db/drizzle.config.ts",
|
"studio": "drizzle-kit studio --config ./server/db/drizzle.config.ts",
|
||||||
"migration:generate": "drizzle-kit generate --config ./server/db/drizzle.config.ts",
|
"migration:generate": "drizzle-kit generate --config ./server/db/drizzle.config.ts",
|
||||||
|
|||||||
@@ -1,47 +1,66 @@
|
|||||||
version: "3.8"
|
|
||||||
services:
|
services:
|
||||||
database:
|
database:
|
||||||
image: postgis/postgis:13-master
|
image: postgis/postgis:13-master
|
||||||
volumes:
|
volumes:
|
||||||
- directus:/var/lib/postgresql/data
|
- directus_database:/var/lib/postgresql/data
|
||||||
networks:
|
networks:
|
||||||
- dokploy-network
|
- dokploy-network
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: "directus"
|
POSTGRES_USER: "directus"
|
||||||
POSTGRES_PASSWORD: "directus"
|
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
|
||||||
POSTGRES_DB: "directus"
|
POSTGRES_DB: "directus"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "pg_isready", "--host=localhost", "--username=directus"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_interval: 5s
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
image: redis:6
|
image: redis:6
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "[ $$(redis-cli ping) = 'PONG' ]"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_interval: 5s
|
||||||
|
start_period: 30s
|
||||||
networks:
|
networks:
|
||||||
- dokploy-network
|
- dokploy-network
|
||||||
|
|
||||||
directus:
|
directus:
|
||||||
image: directus/directus:10.12.1
|
image: directus/directus:11.0.2
|
||||||
ports:
|
ports:
|
||||||
- 8055
|
- 8055
|
||||||
volumes:
|
volumes:
|
||||||
- ../files/uploads:/directus/uploads
|
- directus_uploads:/directus/uploads
|
||||||
- ../files/extensions:/directus/extensions
|
- directus_extensions:/directus/extensions
|
||||||
depends_on:
|
depends_on:
|
||||||
- cache
|
database:
|
||||||
- database
|
condition: service_healthy
|
||||||
|
cache:
|
||||||
|
condition: service_healthy
|
||||||
environment:
|
environment:
|
||||||
SECRET: "replace-with-secure-random-value"
|
SECRET: ${DIRECTUS_SECRET}
|
||||||
|
|
||||||
DB_CLIENT: "pg"
|
DB_CLIENT: "pg"
|
||||||
DB_HOST: "database"
|
DB_HOST: "database"
|
||||||
DB_PORT: "5432"
|
DB_PORT: "5432"
|
||||||
DB_DATABASE: "directus"
|
DB_DATABASE: "directus"
|
||||||
DB_USER: "directus"
|
DB_USER: "directus"
|
||||||
DB_PASSWORD: "directus"
|
DB_PASSWORD: ${DATABASE_PASSWORD}
|
||||||
|
|
||||||
CACHE_ENABLED: "true"
|
CACHE_ENABLED: "true"
|
||||||
CACHE_AUTO_PURGE: "true"
|
CACHE_AUTO_PURGE: "true"
|
||||||
CACHE_STORE: "redis"
|
CACHE_STORE: "redis"
|
||||||
REDIS: "redis://cache:6379"
|
REDIS: "redis://cache:6379"
|
||||||
|
|
||||||
|
# After first successful login, remove the admin email/password env. variables below
|
||||||
|
# as these will now be stored in the database.
|
||||||
ADMIN_EMAIL: "admin@example.com"
|
ADMIN_EMAIL: "admin@example.com"
|
||||||
ADMIN_PASSWORD: "d1r3ctu5"
|
ADMIN_PASSWORD: "d1r3ctu5"
|
||||||
volumes:
|
volumes:
|
||||||
directus:
|
directus_uploads:
|
||||||
|
directus_extensions:
|
||||||
|
directus_database:
|
||||||
@@ -2,10 +2,15 @@ import {
|
|||||||
type DomainSchema,
|
type DomainSchema,
|
||||||
type Schema,
|
type Schema,
|
||||||
type Template,
|
type Template,
|
||||||
|
generateBase64,
|
||||||
|
generatePassword,
|
||||||
generateRandomDomain,
|
generateRandomDomain,
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
|
|
||||||
export function generate(schema: Schema): Template {
|
export function generate(schema: Schema): Template {
|
||||||
|
const directusSecret = generateBase64(64);
|
||||||
|
const databasePassword = generatePassword();
|
||||||
|
|
||||||
const domains: DomainSchema[] = [
|
const domains: DomainSchema[] = [
|
||||||
{
|
{
|
||||||
host: generateRandomDomain(schema),
|
host: generateRandomDomain(schema),
|
||||||
@@ -14,7 +19,13 @@ export function generate(schema: Schema): Template {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const envs = [
|
||||||
|
`DATABASE_PASSWORD=${databasePassword}`,
|
||||||
|
`DIRECTUS_SECRET=${directusSecret}`,
|
||||||
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
domains,
|
domains,
|
||||||
|
envs,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export const templates: TemplateData[] = [
|
|||||||
{
|
{
|
||||||
id: "directus",
|
id: "directus",
|
||||||
name: "Directus",
|
name: "Directus",
|
||||||
version: "10.12.1",
|
version: "11.0.2",
|
||||||
description:
|
description:
|
||||||
"Directus is an open source headless CMS that provides an API-first solution for building custom backends.",
|
"Directus is an open source headless CMS that provides an API-first solution for building custom backends.",
|
||||||
logo: "directus.jpg",
|
logo: "directus.jpg",
|
||||||
|
|||||||
@@ -56,23 +56,23 @@
|
|||||||
},
|
},
|
||||||
"faq": {
|
"faq": {
|
||||||
"title": "Frequently asked questions",
|
"title": "Frequently asked questions",
|
||||||
"des": "If you can’t find what you’re looking for, please submit an issue through our GitHub repository or ask questions on our Discord.",
|
"des": "If you can't find what you're looking for, please submit an issue through our GitHub repository or ask questions on our Discord.",
|
||||||
"q1": "What is dokploy?",
|
"q1": "What is dokploy?",
|
||||||
"a1": "Dokploy is a stable, easy-to-use deployment solution designed to simplify the application management process. Think of Dokploy as a free alternative self-hostable solution to platforms like Heroku, Vercel, and Netlify.",
|
"a1": "Dokploy is a stable, easy-to-use deployment solution designed to simplify the application management process. Think of Dokploy as a free alternative self-hostable solution to platforms like Heroku, Vercel, and Netlify.",
|
||||||
"q2": "Why Choose Dokploy?",
|
"q2": "Why Choose Dokploy?",
|
||||||
"a2": "Simplicity, Flexibility, and Fast",
|
"a2": "Dokploy offers simplicity, flexibility, and speed in application deployment and management.",
|
||||||
"q3": "Is free?",
|
"q3": "Is Dokploy free?",
|
||||||
"a3": "Yes, dokploy is totally free. You can use it for personal projects, small teams, or even for large-scale applications.",
|
"a3": "Yes, Dokploy is totally free. You can use it for personal projects, small teams, or even for large-scale applications.",
|
||||||
"q4": "Is it open source?",
|
"q4": "Is it open source?",
|
||||||
"a4": "Yes, dokploy is open source and free to use.",
|
"a4": "Yes, Dokploy is open source and free to use.",
|
||||||
"q5": "What types of languages can i deploy with dokploy?",
|
"q5": "What types of languages can I deploy with Dokploy?",
|
||||||
"a5": "Dokploy do not restrict programming languages. you are free to choose your preferred language and framework.",
|
"a5": "Dokploy does not restrict programming languages. You are free to choose your preferred language and framework.",
|
||||||
"q6": "How do I request a feature or report a bug?",
|
"q6": "How do I request a feature or report a bug?",
|
||||||
"a6": "Currently we are working on fixing bug fixes, but we will be releasing new features soon. You can also request features or report bugs.",
|
"a6": "To request a feature or report a bug, please create an issue on our GitHub repository or ask in our Discord channel. We are currently focused on addressing existing bugs and plan to release new features soon.",
|
||||||
"q7": "Do you track the usage of Dokploy?",
|
"q7": "Do you track the usage of Dokploy?",
|
||||||
"a7": "No, we don't track any usage data.",
|
"a7": "No, we don't track any usage data.",
|
||||||
"q8": "Are there any user forums or communities where I can interact with other users?",
|
"q8": "Are there any user forums or communities where I can interact with other users?",
|
||||||
"a8": "Yes, we have active github discussions where you can share ideas, ask for help, and connect with other users.",
|
"a8": "Yes, we have active GitHub discussions where you can share ideas, ask for help, and connect with other users.",
|
||||||
"q9": "What types of applications can I deploy with Dokploy?",
|
"q9": "What types of applications can I deploy with Dokploy?",
|
||||||
"a9": "Dokploy supports a variety of applications, including those built with Docker, as well as applications from any Git repository, offering custom builds with Nixpacks, Dockerfiles, or Buildpacks like Heroku and Paketo.",
|
"a9": "Dokploy supports a variety of applications, including those built with Docker, as well as applications from any Git repository, offering custom builds with Nixpacks, Dockerfiles, or Buildpacks like Heroku and Paketo.",
|
||||||
"q10": "How does Dokploy handle database management?",
|
"q10": "How does Dokploy handle database management?",
|
||||||
|
|||||||
@@ -61,6 +61,11 @@ install_dokploy() {
|
|||||||
|
|
||||||
docker swarm init --advertise-addr $advertise_addr
|
docker swarm init --advertise-addr $advertise_addr
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: Failed to initialize Docker Swarm" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Swarm initialized"
|
echo "Swarm initialized"
|
||||||
|
|
||||||
docker network rm -f dokploy-network 2>/dev/null
|
docker network rm -f dokploy-network 2>/dev/null
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ install_dokploy() {
|
|||||||
|
|
||||||
docker swarm init --advertise-addr $advertise_addr
|
docker swarm init --advertise-addr $advertise_addr
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: Failed to initialize Docker Swarm" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Swarm initialized"
|
echo "Swarm initialized"
|
||||||
|
|
||||||
docker network rm -f dokploy-network 2>/dev/null
|
docker network rm -f dokploy-network 2>/dev/null
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ install_dokploy() {
|
|||||||
|
|
||||||
docker swarm init --advertise-addr $advertise_addr
|
docker swarm init --advertise-addr $advertise_addr
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: Failed to initialize Docker Swarm" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Swarm initialized"
|
echo "Swarm initialized"
|
||||||
|
|
||||||
docker network rm -f dokploy-network 2>/dev/null
|
docker network rm -f dokploy-network 2>/dev/null
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ export const cloneBitbucketRepository = async (
|
|||||||
bitbucketBranch!,
|
bitbucketBranch!,
|
||||||
"--depth",
|
"--depth",
|
||||||
"1",
|
"1",
|
||||||
|
"--recurse-submodules",
|
||||||
cloneUrl,
|
cloneUrl,
|
||||||
outputPath,
|
outputPath,
|
||||||
"--progress",
|
"--progress",
|
||||||
@@ -111,6 +112,7 @@ export const cloneRawBitbucketRepository = async (entity: Compose) => {
|
|||||||
bitbucketBranch!,
|
bitbucketBranch!,
|
||||||
"--depth",
|
"--depth",
|
||||||
"1",
|
"1",
|
||||||
|
"--recurse-submodules",
|
||||||
cloneUrl,
|
cloneUrl,
|
||||||
outputPath,
|
outputPath,
|
||||||
"--progress",
|
"--progress",
|
||||||
@@ -153,7 +155,7 @@ export const cloneRawBitbucketRepositoryRemote = async (compose: Compose) => {
|
|||||||
try {
|
try {
|
||||||
const command = `
|
const command = `
|
||||||
rm -rf ${outputPath};
|
rm -rf ${outputPath};
|
||||||
git clone --branch ${bitbucketBranch} --depth 1 ${cloneUrl} ${outputPath}
|
git clone --branch ${bitbucketBranch} --depth 1 --recurse-submodules ${cloneUrl} ${outputPath}
|
||||||
`;
|
`;
|
||||||
await execAsyncRemote(serverId, command);
|
await execAsyncRemote(serverId, command);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -206,7 +208,7 @@ export const getBitbucketCloneCommand = async (
|
|||||||
const cloneCommand = `
|
const cloneCommand = `
|
||||||
rm -rf ${outputPath};
|
rm -rf ${outputPath};
|
||||||
mkdir -p ${outputPath};
|
mkdir -p ${outputPath};
|
||||||
if ! git clone --branch ${bitbucketBranch} --depth 1 --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
|
if ! git clone --branch ${bitbucketBranch} --depth 1 --recurse-submodules --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
|
||||||
echo "❌ [ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
|
echo "❌ [ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ export const getCustomGitCloneCommand = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
command.push(
|
command.push(
|
||||||
`if ! git clone --branch ${customGitBranch} --depth 1 --progress ${customGitUrl} ${outputPath} >> ${logPath} 2>&1; then
|
`if ! git clone --branch ${customGitBranch} --depth 1 --recurse-submodules --progress ${customGitUrl} ${outputPath} >> ${logPath} 2>&1; then
|
||||||
echo "❌ [ERROR] Fail to clone the repository ${customGitUrl}" >> ${logPath};
|
echo "❌ [ERROR] Fail to clone the repository ${customGitUrl}" >> ${logPath};
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
@@ -312,6 +312,7 @@ export const cloneGitRawRepository = async (entity: {
|
|||||||
customGitBranch,
|
customGitBranch,
|
||||||
"--depth",
|
"--depth",
|
||||||
"1",
|
"1",
|
||||||
|
"--recurse-submodules",
|
||||||
customGitUrl,
|
customGitUrl,
|
||||||
outputPath,
|
outputPath,
|
||||||
"--progress",
|
"--progress",
|
||||||
@@ -391,7 +392,7 @@ export const cloneRawGitRepositoryRemote = async (compose: Compose) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
command.push(
|
command.push(
|
||||||
`if ! git clone --branch ${customGitBranch} --depth 1 --progress ${customGitUrl} ${outputPath} ; then
|
`if ! git clone --branch ${customGitBranch} --depth 1 --recurse-submodules --progress ${customGitUrl} ${outputPath} ; then
|
||||||
echo "[ERROR] Fail to clone the repository ";
|
echo "[ERROR] Fail to clone the repository ";
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ export const cloneGithubRepository = async (
|
|||||||
branch!,
|
branch!,
|
||||||
"--depth",
|
"--depth",
|
||||||
"1",
|
"1",
|
||||||
|
"--recurse-submodules",
|
||||||
cloneUrl,
|
cloneUrl,
|
||||||
outputPath,
|
outputPath,
|
||||||
"--progress",
|
"--progress",
|
||||||
@@ -204,7 +205,7 @@ export const getGithubCloneCommand = async (
|
|||||||
const cloneCommand = `
|
const cloneCommand = `
|
||||||
rm -rf ${outputPath};
|
rm -rf ${outputPath};
|
||||||
mkdir -p ${outputPath};
|
mkdir -p ${outputPath};
|
||||||
if ! git clone --branch ${branch} --depth 1 --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
|
if ! git clone --branch ${branch} --depth 1 --recurse-submodules --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
|
||||||
echo "❌ [ERROR] Fallo al clonar el repositorio ${repoclone}" >> ${logPath};
|
echo "❌ [ERROR] Fallo al clonar el repositorio ${repoclone}" >> ${logPath};
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
@@ -239,6 +240,7 @@ export const cloneRawGithubRepository = async (entity: Compose) => {
|
|||||||
branch!,
|
branch!,
|
||||||
"--depth",
|
"--depth",
|
||||||
"1",
|
"1",
|
||||||
|
"--recurse-submodules",
|
||||||
cloneUrl,
|
cloneUrl,
|
||||||
outputPath,
|
outputPath,
|
||||||
"--progress",
|
"--progress",
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ export const cloneGitlabRepository = async (
|
|||||||
gitlabBranch!,
|
gitlabBranch!,
|
||||||
"--depth",
|
"--depth",
|
||||||
"1",
|
"1",
|
||||||
|
"--recurse-submodules",
|
||||||
cloneUrl,
|
cloneUrl,
|
||||||
outputPath,
|
outputPath,
|
||||||
"--progress",
|
"--progress",
|
||||||
@@ -225,7 +226,7 @@ export const getGitlabCloneCommand = async (
|
|||||||
const cloneCommand = `
|
const cloneCommand = `
|
||||||
rm -rf ${outputPath};
|
rm -rf ${outputPath};
|
||||||
mkdir -p ${outputPath};
|
mkdir -p ${outputPath};
|
||||||
if ! git clone --branch ${gitlabBranch} --depth 1 --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
|
if ! git clone --branch ${gitlabBranch} --depth 1 --recurse-submodules --progress ${cloneUrl} ${outputPath} >> ${logPath} 2>&1; then
|
||||||
echo "❌ [ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
|
echo "❌ [ERROR] Fail to clone the repository ${repoclone}" >> ${logPath};
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
@@ -361,6 +362,7 @@ export const cloneRawGitlabRepository = async (entity: Compose) => {
|
|||||||
gitlabBranch!,
|
gitlabBranch!,
|
||||||
"--depth",
|
"--depth",
|
||||||
"1",
|
"1",
|
||||||
|
"--recurse-submodules",
|
||||||
cloneUrl,
|
cloneUrl,
|
||||||
outputPath,
|
outputPath,
|
||||||
"--progress",
|
"--progress",
|
||||||
@@ -395,7 +397,7 @@ export const cloneRawGitlabRepositoryRemote = async (compose: Compose) => {
|
|||||||
try {
|
try {
|
||||||
const command = `
|
const command = `
|
||||||
rm -rf ${outputPath};
|
rm -rf ${outputPath};
|
||||||
git clone --branch ${branch} --depth 1 ${cloneUrl} ${outputPath}
|
git clone --branch ${branch} --depth 1 --recurse-submodules ${cloneUrl} ${outputPath}
|
||||||
`;
|
`;
|
||||||
await execAsyncRemote(serverId, command);
|
await execAsyncRemote(serverId, command);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user