vps-deployer 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/app.d.ts +4 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +39 -0
- package/dist/app.js.map +1 -0
- package/dist/db/db.d.ts +5 -0
- package/dist/db/db.d.ts.map +1 -0
- package/dist/db/db.js +100 -0
- package/dist/db/db.js.map +1 -0
- package/dist/helpers/arg.helper.d.ts +7 -0
- package/dist/helpers/arg.helper.d.ts.map +1 -0
- package/dist/helpers/arg.helper.js +28 -0
- package/dist/helpers/arg.helper.js.map +1 -0
- package/dist/helpers/cmd_executer.helper.d.ts +7 -0
- package/dist/helpers/cmd_executer.helper.d.ts.map +1 -0
- package/dist/helpers/cmd_executer.helper.js +88 -0
- package/dist/helpers/cmd_executer.helper.js.map +1 -0
- package/dist/helpers/common.helper.d.ts +2 -0
- package/dist/helpers/common.helper.d.ts.map +1 -0
- package/dist/helpers/common.helper.js +15 -0
- package/dist/helpers/common.helper.js.map +1 -0
- package/dist/helpers/config_files.helper.d.ts +2 -0
- package/dist/helpers/config_files.helper.d.ts.map +1 -0
- package/dist/helpers/config_files.helper.js +44 -0
- package/dist/helpers/config_files.helper.js.map +1 -0
- package/dist/helpers/create_systemd_service.helper.d.ts +9 -0
- package/dist/helpers/create_systemd_service.helper.d.ts.map +1 -0
- package/dist/helpers/create_systemd_service.helper.js +40 -0
- package/dist/helpers/create_systemd_service.helper.js.map +1 -0
- package/dist/helpers/date.helper.d.ts +2 -0
- package/dist/helpers/date.helper.d.ts.map +1 -0
- package/dist/helpers/date.helper.js +18 -0
- package/dist/helpers/date.helper.js.map +1 -0
- package/dist/helpers/email.helper.d.ts +11 -0
- package/dist/helpers/email.helper.d.ts.map +1 -0
- package/dist/helpers/email.helper.js +144 -0
- package/dist/helpers/email.helper.js.map +1 -0
- package/dist/helpers/logging.helper.d.ts +9 -0
- package/dist/helpers/logging.helper.d.ts.map +1 -0
- package/dist/helpers/logging.helper.js +32 -0
- package/dist/helpers/logging.helper.js.map +1 -0
- package/dist/helpers/remove_systemd_service.helper.d.ts +2 -0
- package/dist/helpers/remove_systemd_service.helper.d.ts.map +1 -0
- package/dist/helpers/remove_systemd_service.helper.js +21 -0
- package/dist/helpers/remove_systemd_service.helper.js.map +1 -0
- package/dist/helpers/start_systemd_service.helper.d.ts +2 -0
- package/dist/helpers/start_systemd_service.helper.d.ts.map +1 -0
- package/dist/helpers/start_systemd_service.helper.js +26 -0
- package/dist/helpers/start_systemd_service.helper.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +132 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/auth.middleware.d.ts +3 -0
- package/dist/middleware/auth.middleware.d.ts.map +1 -0
- package/dist/middleware/auth.middleware.js +7 -0
- package/dist/middleware/auth.middleware.js.map +1 -0
- package/dist/modules/auth/auth.route.d.ts +3 -0
- package/dist/modules/auth/auth.route.d.ts.map +1 -0
- package/dist/modules/auth/auth.route.js +16 -0
- package/dist/modules/auth/auth.route.js.map +1 -0
- package/dist/modules/auth/controllers/auth.controller.d.ts +6 -0
- package/dist/modules/auth/controllers/auth.controller.d.ts.map +1 -0
- package/dist/modules/auth/controllers/auth.controller.js +123 -0
- package/dist/modules/auth/controllers/auth.controller.js.map +1 -0
- package/dist/modules/auth/views/login.pug +254 -0
- package/dist/modules/auth/views/register.pug +298 -0
- package/dist/modules/common/views/404.pug +21 -0
- package/dist/modules/dashboard/dashboard.route.d.ts +3 -0
- package/dist/modules/dashboard/dashboard.route.d.ts.map +1 -0
- package/dist/modules/dashboard/dashboard.route.js +29 -0
- package/dist/modules/dashboard/dashboard.route.js.map +1 -0
- package/dist/modules/dashboard/views/dash.pug +149 -0
- package/dist/modules/dashboard/views/layout.pug +94 -0
- package/dist/modules/deployer/controllers/deployer.controller.d.ts +6 -0
- package/dist/modules/deployer/controllers/deployer.controller.d.ts.map +1 -0
- package/dist/modules/deployer/controllers/deployer.controller.js +119 -0
- package/dist/modules/deployer/controllers/deployer.controller.js.map +1 -0
- package/dist/modules/deployer/deployer.route.d.ts +3 -0
- package/dist/modules/deployer/deployer.route.d.ts.map +1 -0
- package/dist/modules/deployer/deployer.route.js +13 -0
- package/dist/modules/deployer/deployer.route.js.map +1 -0
- package/dist/modules/deployer/helper/deployer.d.ts +9 -0
- package/dist/modules/deployer/helper/deployer.d.ts.map +1 -0
- package/dist/modules/deployer/helper/deployer.js +89 -0
- package/dist/modules/deployer/helper/deployer.js.map +1 -0
- package/dist/modules/deployer/views/details.pug +157 -0
- package/dist/modules/deployer/views/index.pug +108 -0
- package/dist/modules/project/controllers/projects.controller.d.ts +12 -0
- package/dist/modules/project/controllers/projects.controller.d.ts.map +1 -0
- package/dist/modules/project/controllers/projects.controller.js +267 -0
- package/dist/modules/project/controllers/projects.controller.js.map +1 -0
- package/dist/modules/project/helper/project_file_sys.helper.d.ts +7 -0
- package/dist/modules/project/helper/project_file_sys.helper.d.ts.map +1 -0
- package/dist/modules/project/helper/project_file_sys.helper.js +93 -0
- package/dist/modules/project/helper/project_file_sys.helper.js.map +1 -0
- package/dist/modules/project/project.route.d.ts +3 -0
- package/dist/modules/project/project.route.d.ts.map +1 -0
- package/dist/modules/project/project.route.js +17 -0
- package/dist/modules/project/project.route.js.map +1 -0
- package/dist/modules/project/views/create.pug +189 -0
- package/dist/modules/project/views/details.pug +238 -0
- package/dist/modules/project/views/index.pug +114 -0
- package/dist/modules/settings/controllers/setting.controller.d.ts +5 -0
- package/dist/modules/settings/controllers/setting.controller.d.ts.map +1 -0
- package/dist/modules/settings/controllers/setting.controller.js +193 -0
- package/dist/modules/settings/controllers/setting.controller.js.map +1 -0
- package/dist/modules/settings/settings.route.d.ts +3 -0
- package/dist/modules/settings/settings.route.d.ts.map +1 -0
- package/dist/modules/settings/settings.route.js +10 -0
- package/dist/modules/settings/settings.route.js.map +1 -0
- package/dist/modules/settings/views/index.pug +173 -0
- package/dist/modules/webhook/controllers/webhook.controller.d.ts +3 -0
- package/dist/modules/webhook/controllers/webhook.controller.d.ts.map +1 -0
- package/dist/modules/webhook/controllers/webhook.controller.js +72 -0
- package/dist/modules/webhook/controllers/webhook.controller.js.map +1 -0
- package/dist/modules/webhook/webhook.route.d.ts +3 -0
- package/dist/modules/webhook/webhook.route.d.ts.map +1 -0
- package/dist/modules/webhook/webhook.route.js +6 -0
- package/dist/modules/webhook/webhook.route.js.map +1 -0
- package/dist/utils/app_config.d.ts +3 -0
- package/dist/utils/app_config.d.ts.map +1 -0
- package/dist/utils/app_config.js +5 -0
- package/dist/utils/app_config.js.map +1 -0
- package/dist/utils/cli.d.ts +2 -0
- package/dist/utils/cli.d.ts.map +1 -0
- package/dist/utils/cli.js +68 -0
- package/dist/utils/cli.js.map +1 -0
- package/package.json +80 -0
- package/public/favicon.svg +18 -0
- package/public/js/deploy.js +36 -0
- package/public/js/deployment-details.js +56 -0
- package/public/js/login.js +21 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 0xv1shal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/0xv1shal/vps-deployer/main/public/favicon.svg" alt="VPS Deployer Logo" width="120" />
|
|
3
|
+
<h1 align="center">VPS Deployer</h1>
|
|
4
|
+
<p align="center"><strong>Deployment made easy.</strong></p>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
A lightweight, self-hosted continuous deployment (CD) system with a built-in web UI — manages projects on your VPS, accepts GitHub webhooks for automatic deployments, and sends real-time email notifications on deployment events.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/vps-deployer"><img src="https://img.shields.io/npm/v/vps-deployer.svg?style=flat-square&color=cb3837" alt="npm version" /></a>
|
|
13
|
+
<a href="https://nodejs.org/en/about/releases/"><img src="https://img.shields.io/node/v/vps-deployer.svg?style=flat-square&color=339933" alt="Node.js version" /></a>
|
|
14
|
+
<a href="https://github.com/0xv1shal/vps-deployer/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/vps-deployer.svg?style=flat-square&color=blue" alt="License" /></a>
|
|
15
|
+
<a href="https://github.com/0xv1shal/vps-deployer"><img src="https://img.shields.io/badge/platform-linux-lightgrey.svg?style=flat-square" alt="Platform" /></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
| | |
|
|
23
|
+
|---|---|
|
|
24
|
+
| 🖥️ **Web UI Dashboard** | Monitor projects, deployments, and logs from your browser |
|
|
25
|
+
| 🔄 **GitHub Webhooks** | Push to a branch and let VPS Deployer handle the rest |
|
|
26
|
+
| 📧 **Email Notifications** | Get notified on deployment success or failure via SMTP |
|
|
27
|
+
| ⚙️ **Custom Build Commands** | Define per-project command sequences (build, migrate, restart) |
|
|
28
|
+
| 🔐 **Per-Project Env Vars** | Manage `.env` files through the UI |
|
|
29
|
+
| 🪶 **Lightweight** | Single SQLite database, no external services required |
|
|
30
|
+
| 🚀 **CLI-Driven** | Start with a single command, manage everything from the web |
|
|
31
|
+
|
|
32
|
+
## Prerequisites
|
|
33
|
+
|
|
34
|
+
- **Linux** (requires `root`/`sudo` for systemd service creation)
|
|
35
|
+
- **Node.js** >= 18
|
|
36
|
+
- **npm** or **pnpm**
|
|
37
|
+
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install -g vps-deployer
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Generate Configs
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
sudo vps-deployer -w /opt/vps-deployer -p 3000 -s your-super-secret-session-key
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This creates the systemd service file, database, and reference configs, then exits.
|
|
53
|
+
|
|
54
|
+
| Flag | Description |
|
|
55
|
+
|------|-------------|
|
|
56
|
+
| `-w, --working-dir` | Directory where projects and data will be stored |
|
|
57
|
+
| `-p, --port` | Port for the web UI and API (1024–50000) |
|
|
58
|
+
| `-s, --session-key` | Secret key for session encryption (min 6 characters) |
|
|
59
|
+
| `--dev` | Run in development mode (foreground, no systemd) |
|
|
60
|
+
|
|
61
|
+
### 3. Start the Service
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
sudo vps-deployer start
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This enables and starts the systemd service. The terminal is freed immediately.
|
|
68
|
+
|
|
69
|
+
> **Dev mode:** To run in the foreground without systemd, use `sudo vps-deployer -w /opt/vps-deployer -p 3000 -s key --dev`
|
|
70
|
+
|
|
71
|
+
### 4. Open the Web UI
|
|
72
|
+
|
|
73
|
+
Navigate to `http://<your-server-ip>:3000` and register your account.
|
|
74
|
+
|
|
75
|
+
### 5. Create a Project
|
|
76
|
+
|
|
77
|
+
1. Go to **Projects** → **Create**
|
|
78
|
+
2. Enter your GitHub repo URL and branch name
|
|
79
|
+
3. Add build/deploy commands (e.g., `npm install`, `npm run build`, `pm2 restart app`)
|
|
80
|
+
4. Save — your unique webhook URL and secret will be displayed
|
|
81
|
+
|
|
82
|
+
### 6. Configure the Webhook
|
|
83
|
+
|
|
84
|
+
Copy the webhook URL and secret from the project details page, then add them to your GitHub repo:
|
|
85
|
+
|
|
86
|
+
`Settings → Webhooks → Add webhook → Paste URL → Set Content type to application/json → Paste Secret`
|
|
87
|
+
|
|
88
|
+
### 7. Deploy
|
|
89
|
+
|
|
90
|
+
Push to your configured branch. VPS Deployer will receive the webhook, run your commands, and notify you via email.
|
|
91
|
+
|
|
92
|
+
> **Important:** VPS Deployer does **not** automatically pull your repository on webhook receipt. You must explicitly add a `git pull` (or `git clone`) command as the first step in your project's command list. For example:
|
|
93
|
+
>
|
|
94
|
+
> ```
|
|
95
|
+
> 1. git pull origin main
|
|
96
|
+
> 2. npm install
|
|
97
|
+
> 3. npm run build
|
|
98
|
+
> ```
|
|
99
|
+
|
|
100
|
+
## Screenshots
|
|
101
|
+
|
|
102
|
+
> 
|
|
103
|
+
>
|
|
104
|
+
> *Dashboard with project stats and recent deployments*
|
|
105
|
+
|
|
106
|
+
> 
|
|
107
|
+
>
|
|
108
|
+
> *Project configuration with commands and environment variables*
|
|
109
|
+
|
|
110
|
+
> 
|
|
111
|
+
>
|
|
112
|
+
> *Real-time deployment log output*
|
|
113
|
+
|
|
114
|
+
## Project Structure
|
|
115
|
+
|
|
116
|
+
When you run VPS Deployer, it creates the following structure in your working directory:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
/opt/vps-deployer/
|
|
120
|
+
├── data.db # SQLite database
|
|
121
|
+
├── caddy.config # Generated reverse proxy config
|
|
122
|
+
├── nginx.config # Generated reverse proxy config
|
|
123
|
+
├── systemd.file.copy.txt # Systemd unit file reference
|
|
124
|
+
└── <project-id>/ # Per-project workspace
|
|
125
|
+
├── .env # Environment variables
|
|
126
|
+
└── ... # Cloned repository files
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Documentation
|
|
130
|
+
|
|
131
|
+
| Document | Description |
|
|
132
|
+
|----------|-------------|
|
|
133
|
+
| [Quick Start](https://github.com/0xv1shal/vps-deployer/blob/main/docs/quick-start.md) | Step-by-step walkthrough from install to first deployment |
|
|
134
|
+
| [CLI Reference](https://github.com/0xv1shal/vps-deployer/blob/main/docs/cli-reference.md) | All flags, validation rules, and examples |
|
|
135
|
+
| [Webhook Setup](https://github.com/0xv1shal/vps-deployer/blob/main/docs/webhook-setup.md) | Configure GitHub webhooks for auto-deployment |
|
|
136
|
+
| [Email Setup](https://github.com/0xv1shal/vps-deployer/blob/main/docs/email-setup.md) | Configure SMTP for deployment notifications |
|
|
137
|
+
| [Architecture](https://github.com/0xv1shal/vps-deployer/blob/main/docs/architecture.md) | System design, database schema, and deployment flow |
|
|
138
|
+
| [Database Schema](https://github.com/0xv1shal/vps-deployer/blob/main/docs/schema.md) | Full table definitions |
|
|
139
|
+
|
|
140
|
+
## Security
|
|
141
|
+
|
|
142
|
+
- This tool **must be run as root** to create systemd services and execute deployment commands
|
|
143
|
+
- The web UI is protected by session-based authentication (login/register)
|
|
144
|
+
- Rate limiting is applied on auth endpoints (40 req/min per IP)
|
|
145
|
+
- Every webhook is verified using HMAC-SHA256 with a per-project secret
|
|
146
|
+
- Use a strong, unique session key (`-s` flag)
|
|
147
|
+
- Keep the working directory restricted to the tool only
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT — see [LICENSE](https://github.com/0xv1shal/vps-deployer/blob/main/LICENSE) for details.
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAYA,QAAA,MAAM,GAAG,6CAAY,CAAC;AAUtB,eAAe,GAAG,CAAC;AAEnB,eAAO,MAAM,oBAAoB,GAAI,KAAK,GAAG,SAsB5C,CAAC"}
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import express, {} from "express";
|
|
2
|
+
import helmet from "helmet";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import session from "express-session";
|
|
5
|
+
import authRouter from "./modules/auth/auth.route.js";
|
|
6
|
+
import dashboardRouter from "./modules/dashboard/dashboard.route.js";
|
|
7
|
+
import projectRouter from "./modules/project/project.route.js";
|
|
8
|
+
import settingsRouter from "./modules/settings/settings.route.js";
|
|
9
|
+
import deployRouter from "./modules/deployer/deployer.route.js";
|
|
10
|
+
import webhookRouter from "./modules/webhook/webhook.route.js";
|
|
11
|
+
import { getSessKey } from "./helpers/arg.helper.js";
|
|
12
|
+
const app = express();
|
|
13
|
+
const basePath = import.meta.dirname;
|
|
14
|
+
app.set("view engine", "pug");
|
|
15
|
+
app.set("views", path.join(basePath, "modules"));
|
|
16
|
+
app.use(express.static(path.join(basePath, "..", "public")));
|
|
17
|
+
app.use(helmet());
|
|
18
|
+
app.use(express.json());
|
|
19
|
+
app.use(express.urlencoded({ extended: true }));
|
|
20
|
+
export default app;
|
|
21
|
+
export const initSessionAndRoutes = (app) => {
|
|
22
|
+
const sessionKey = getSessKey();
|
|
23
|
+
app.use(session({
|
|
24
|
+
secret: sessionKey,
|
|
25
|
+
resave: false,
|
|
26
|
+
saveUninitialized: false,
|
|
27
|
+
cookie: { secure: "auto" },
|
|
28
|
+
}));
|
|
29
|
+
app.use(dashboardRouter);
|
|
30
|
+
app.use(authRouter);
|
|
31
|
+
app.use(projectRouter);
|
|
32
|
+
app.use(settingsRouter);
|
|
33
|
+
app.use(deployRouter);
|
|
34
|
+
app.use(webhookRouter);
|
|
35
|
+
app.use((_req, res) => {
|
|
36
|
+
res.status(404).render("common/views/404");
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,EAAE,EAA+B,MAAM,SAAS,CAAC;AAC/D,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,OAAO,MAAM,iBAAiB,CAAC;AACtC,OAAO,UAAU,MAAM,8BAA8B,CAAC;AACtD,OAAO,eAAe,MAAM,wCAAwC,CAAC;AACrE,OAAO,aAAa,MAAM,oCAAoC,CAAC;AAC/D,OAAO,cAAc,MAAM,sCAAsC,CAAC;AAClE,OAAO,YAAY,MAAM,sCAAsC,CAAC;AAChE,OAAO,aAAa,MAAM,oCAAoC,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;AACtB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;AAErC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;AAC9B,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;AACjD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC7D,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;AAClB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AACxB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAEhD,eAAe,GAAG,CAAC;AAEnB,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,GAAQ,EAAE,EAAE;IAC/C,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC;IAEhC,GAAG,CAAC,GAAG,CACL,OAAO,CAAC;QACN,MAAM,EAAE,UAAU;QAClB,MAAM,EAAE,KAAK;QACb,iBAAiB,EAAE,KAAK;QACxB,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;KAC3B,CAAC,CACH,CAAC;IAEF,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACzB,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpB,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACvB,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACxB,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACtB,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAEvB,GAAG,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;QACvC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
package/dist/db/db.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,QAAQ,IAAI,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAqFzD,eAAO,MAAM,WAAW,YAMvB,CAAC;AAEF,eAAO,MAAM,KAAK,QAAO,MAIxB,CAAC;AAEF,eAAO,MAAM,OAAO,YAEnB,CAAC"}
|
package/dist/db/db.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import {} from "better-sqlite3";
|
|
4
|
+
import { getWorkDirPath } from "../helpers/arg.helper.js";
|
|
5
|
+
let DB = null;
|
|
6
|
+
const createTables = () => {
|
|
7
|
+
if (!DB)
|
|
8
|
+
throw new Error("DB not initialized");
|
|
9
|
+
DB.exec(`
|
|
10
|
+
CREATE TABLE IF NOT EXISTS user (
|
|
11
|
+
id TEXT PRIMARY KEY,
|
|
12
|
+
username TEXT NOT NULL,
|
|
13
|
+
password TEXT NOT NULL,
|
|
14
|
+
email TEXT NOT NULL,
|
|
15
|
+
last_logged_in TEXT DEFAULT (datetime('now')),
|
|
16
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
CREATE TABLE IF NOT EXISTS email (
|
|
20
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
21
|
+
username TEXT,
|
|
22
|
+
password TEXT,
|
|
23
|
+
smtp TEXT,
|
|
24
|
+
smtp_port INTEGER,
|
|
25
|
+
"from" TEXT
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
CREATE TABLE IF NOT EXISTS project (
|
|
29
|
+
id TEXT PRIMARY KEY,
|
|
30
|
+
name TEXT NOT NULL,
|
|
31
|
+
github_url TEXT NOT NULL,
|
|
32
|
+
branch_name TEXT NOT NULL,
|
|
33
|
+
receive_email_notf INTEGER DEFAULT 0 CHECK (receive_email_notf IN (0,1)),
|
|
34
|
+
auto_deploy INTEGER DEFAULT 0 CHECK (auto_deploy IN (0,1)),
|
|
35
|
+
webhook_secret TEXT NOT NULL UNIQUE
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
CREATE TABLE IF NOT EXISTS project_commands (
|
|
39
|
+
id TEXT PRIMARY KEY,
|
|
40
|
+
proj_id TEXT NOT NULL,
|
|
41
|
+
seq_no INTEGER NOT NULL,
|
|
42
|
+
cmd TEXT NOT NULL,
|
|
43
|
+
FOREIGN KEY (proj_id) REFERENCES project(id) ON DELETE CASCADE
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
CREATE TABLE IF NOT EXISTS project_env (
|
|
47
|
+
id TEXT PRIMARY KEY,
|
|
48
|
+
proj_id TEXT NOT NULL,
|
|
49
|
+
key TEXT NOT NULL,
|
|
50
|
+
value TEXT NOT NULL,
|
|
51
|
+
FOREIGN KEY (proj_id) REFERENCES project(id) ON DELETE CASCADE,
|
|
52
|
+
UNIQUE (proj_id, key)
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
CREATE TABLE IF NOT EXISTS deployment (
|
|
56
|
+
id TEXT PRIMARY KEY,
|
|
57
|
+
proj_id TEXT NOT NULL,
|
|
58
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
59
|
+
finished_at TEXT,
|
|
60
|
+
status TEXT CHECK (status IN ('running','success','failed')) NOT NULL DEFAULT 'running',
|
|
61
|
+
FOREIGN KEY (proj_id) REFERENCES project(id) ON DELETE CASCADE
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
CREATE TABLE IF NOT EXISTS deployment_logs (
|
|
65
|
+
id TEXT PRIMARY KEY,
|
|
66
|
+
deploy_id TEXT NOT NULL,
|
|
67
|
+
cmd TEXT NOT NULL,
|
|
68
|
+
log TEXT,
|
|
69
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
70
|
+
finished_at TEXT,
|
|
71
|
+
status TEXT CHECK (status IN ('running','success','failed')) NOT NULL DEFAULT 'running',
|
|
72
|
+
FOREIGN KEY (deploy_id) REFERENCES deployment(id) ON DELETE CASCADE
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_project_commands_proj_id
|
|
76
|
+
ON project_commands(proj_id);
|
|
77
|
+
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_deployment_proj_id
|
|
79
|
+
ON deployment(proj_id);
|
|
80
|
+
|
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_deployment_logs_deploy_id
|
|
82
|
+
ON deployment_logs(deploy_id);
|
|
83
|
+
`);
|
|
84
|
+
};
|
|
85
|
+
export const initalizeDB = () => {
|
|
86
|
+
const workingDir = getWorkDirPath();
|
|
87
|
+
const dbPath = path.join(workingDir, "vps-deployer.db");
|
|
88
|
+
DB = new Database(dbPath);
|
|
89
|
+
DB.pragma("journal_mode = WAL");
|
|
90
|
+
createTables();
|
|
91
|
+
};
|
|
92
|
+
export const getDB = () => {
|
|
93
|
+
if (DB === null)
|
|
94
|
+
throw new Error("DB not initalized");
|
|
95
|
+
return DB;
|
|
96
|
+
};
|
|
97
|
+
export const closeDB = () => {
|
|
98
|
+
DB?.close();
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAA2B,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,IAAI,EAAE,GAAkB,IAAI,CAAC;AAE7B,MAAM,YAAY,GAAG,GAAG,EAAE;IACxB,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAE/C,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EP,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE;IAC9B,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,iBAAiB,CAAC,CAAC;IACxD,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,YAAY,EAAE,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAAG,GAAW,EAAE;IAChC,IAAI,EAAE,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAEtD,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,EAAE;IAC1B,EAAE,EAAE,KAAK,EAAE,CAAC;AACd,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const setWorkDirPath: (path: string) => void;
|
|
2
|
+
export declare const getWorkDirPath: () => string;
|
|
3
|
+
export declare const setPort: (port: number) => void;
|
|
4
|
+
export declare const setSessKey: (sessKey: string) => void;
|
|
5
|
+
export declare const getSessKey: () => string;
|
|
6
|
+
export declare const getPort: () => number;
|
|
7
|
+
//# sourceMappingURL=arg.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arg.helper.d.ts","sourceRoot":"","sources":["../../src/helpers/arg.helper.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc,GAAI,MAAK,MAAM,SAEzC,CAAA;AAED,eAAO,MAAM,cAAc,cAG1B,CAAA;AAED,eAAO,MAAM,OAAO,GAAI,MAAK,MAAM,SAElC,CAAA;AACD,eAAO,MAAM,UAAU,GAAI,SAAQ,MAAM,SAExC,CAAA;AAED,eAAO,MAAM,UAAU,cAGtB,CAAA;AAED,eAAO,MAAM,OAAO,cAGnB,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
let DIR_PATH = '';
|
|
2
|
+
let PORT = 0;
|
|
3
|
+
let SESS_KEY = '';
|
|
4
|
+
export const setWorkDirPath = (path) => {
|
|
5
|
+
DIR_PATH = path;
|
|
6
|
+
};
|
|
7
|
+
export const getWorkDirPath = () => {
|
|
8
|
+
if (DIR_PATH.trim() === '')
|
|
9
|
+
throw new Error('DIR_PATH is not set');
|
|
10
|
+
return DIR_PATH;
|
|
11
|
+
};
|
|
12
|
+
export const setPort = (port) => {
|
|
13
|
+
PORT = port;
|
|
14
|
+
};
|
|
15
|
+
export const setSessKey = (sessKey) => {
|
|
16
|
+
SESS_KEY = sessKey;
|
|
17
|
+
};
|
|
18
|
+
export const getSessKey = () => {
|
|
19
|
+
if (SESS_KEY.trim() === '')
|
|
20
|
+
throw new Error('SESS_KEY is not set, please set it using -s | --session-key <sessKey> flag');
|
|
21
|
+
return SESS_KEY;
|
|
22
|
+
};
|
|
23
|
+
export const getPort = () => {
|
|
24
|
+
if (PORT === 0)
|
|
25
|
+
throw new Error('PORT is not set');
|
|
26
|
+
return PORT;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=arg.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arg.helper.js","sourceRoot":"","sources":["../../src/helpers/arg.helper.ts"],"names":[],"mappings":"AAAA,IAAI,QAAQ,GAAG,EAAE,CAAA;AACjB,IAAI,IAAI,GAAG,CAAC,CAAA;AACZ,IAAI,QAAQ,GAAG,EAAE,CAAA;AAEjB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAW,EAAC,EAAE;IACzC,QAAQ,GAAG,IAAI,CAAA;AACnB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,GAAE,EAAE;IAC9B,IAAG,QAAQ,CAAC,IAAI,EAAE,KAAG,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAA;IAC/D,OAAO,QAAQ,CAAA;AACnB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAW,EAAC,EAAE;IAClC,IAAI,GAAG,IAAI,CAAA;AACf,CAAC,CAAA;AACD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAc,EAAC,EAAE;IACxC,QAAQ,GAAG,OAAO,CAAA;AACtB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,GAAE,EAAE;IAC1B,IAAG,QAAQ,CAAC,IAAI,EAAE,KAAG,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,4EAA4E,CAAC,CAAA;IACtH,OAAO,QAAQ,CAAA;AACnB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,GAAE,EAAE;IACvB,IAAG,IAAI,KAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IAC/C,OAAO,IAAI,CAAA;AACf,CAAC,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const dangerCmdDetector: (cmd: string) => boolean;
|
|
2
|
+
export declare const runCmd: (cmd: string, projDir: string, deployId: string) => Promise<{
|
|
3
|
+
stdout: string;
|
|
4
|
+
stderr: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare const runCmdSeq: (commands: string[], projDir: string, deployId: string) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=cmd_executer.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmd_executer.helper.d.ts","sourceRoot":"","sources":["../../src/helpers/cmd_executer.helper.ts"],"names":[],"mappings":"AA6BA,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,YAU5C,CAAC;AAEF,eAAO,MAAM,MAAM,GACjB,KAAK,MAAM,EACX,SAAS,MAAM,EACf,UAAU,MAAM;YAYa,MAAM;YAAU,MAAM;EA2DpD,CAAC;AAEF,eAAO,MAAM,SAAS,GACpB,UAAU,MAAM,EAAE,EAClB,SAAS,MAAM,EACf,UAAU,MAAM,kBAKjB,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
import { getDB } from "../db/db.js";
|
|
3
|
+
const startCmdLog = (deployId, cmd) => {
|
|
4
|
+
const db = getDB();
|
|
5
|
+
const id = crypto.randomUUID();
|
|
6
|
+
db.prepare(`
|
|
7
|
+
INSERT INTO deployment_logs (id, deploy_id, cmd,status)
|
|
8
|
+
VALUES (?, ?, ?,?)
|
|
9
|
+
`).run(id, deployId, cmd, 'running');
|
|
10
|
+
return id;
|
|
11
|
+
};
|
|
12
|
+
const finishCmdLog = (logId, log, status) => {
|
|
13
|
+
const db = getDB();
|
|
14
|
+
db.prepare(`
|
|
15
|
+
UPDATE deployment_logs
|
|
16
|
+
SET log = ?, status = ?, finished_at = datetime('now')
|
|
17
|
+
WHERE id = ?
|
|
18
|
+
`).run(log, status, logId);
|
|
19
|
+
};
|
|
20
|
+
export const dangerCmdDetector = (cmd) => {
|
|
21
|
+
const dangerous = [
|
|
22
|
+
"rm -rf /",
|
|
23
|
+
"shutdown",
|
|
24
|
+
"reboot",
|
|
25
|
+
"mkfs",
|
|
26
|
+
":(){:|:&};:", // fork bomb
|
|
27
|
+
];
|
|
28
|
+
return dangerous.some((d) => cmd.includes(d));
|
|
29
|
+
};
|
|
30
|
+
export const runCmd = (cmd, projDir, deployId) => {
|
|
31
|
+
if (dangerCmdDetector(cmd)) {
|
|
32
|
+
throw new Error("Dangerous command blocked");
|
|
33
|
+
}
|
|
34
|
+
const logId = startCmdLog(deployId, cmd);
|
|
35
|
+
let stderr = "";
|
|
36
|
+
let stdout = "";
|
|
37
|
+
let isFinished = false;
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const child = spawn(cmd, {
|
|
40
|
+
cwd: projDir,
|
|
41
|
+
shell: true,
|
|
42
|
+
});
|
|
43
|
+
// ⏱️ 5 min timeout
|
|
44
|
+
const timeout = setTimeout(() => {
|
|
45
|
+
if (!isFinished) {
|
|
46
|
+
child.kill("SIGKILL");
|
|
47
|
+
}
|
|
48
|
+
}, 5 * 60 * 1000);
|
|
49
|
+
child.stdout.on("data", (data) => {
|
|
50
|
+
stdout += data.toString();
|
|
51
|
+
});
|
|
52
|
+
child.stderr.on("data", (data) => {
|
|
53
|
+
stderr += data.toString();
|
|
54
|
+
});
|
|
55
|
+
child.on("error", async (err) => {
|
|
56
|
+
if (isFinished)
|
|
57
|
+
return;
|
|
58
|
+
isFinished = true;
|
|
59
|
+
clearTimeout(timeout);
|
|
60
|
+
finishCmdLog(logId, err.message, "failed");
|
|
61
|
+
reject(new Error(`Failed to exec ${cmd}: ${err.message}`));
|
|
62
|
+
});
|
|
63
|
+
child.on("close", async (code, signal) => {
|
|
64
|
+
if (isFinished)
|
|
65
|
+
return;
|
|
66
|
+
isFinished = true;
|
|
67
|
+
clearTimeout(timeout);
|
|
68
|
+
const combinedLog = stdout + "\n" + stderr;
|
|
69
|
+
// If killed by timeout
|
|
70
|
+
if (signal === "SIGKILL") {
|
|
71
|
+
finishCmdLog(logId, combinedLog + "\n[Timeout: Killed]", "failed");
|
|
72
|
+
return reject(new Error(`Command timed out: ${cmd}`));
|
|
73
|
+
}
|
|
74
|
+
if (code === 0) {
|
|
75
|
+
finishCmdLog(logId, combinedLog, "success");
|
|
76
|
+
return resolve({ stdout, stderr });
|
|
77
|
+
}
|
|
78
|
+
finishCmdLog(logId, combinedLog, "failed");
|
|
79
|
+
reject(new Error(stderr.trim() || `Command failed: ${cmd} (code ${code})`));
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
export const runCmdSeq = async (commands, projDir, deployId) => {
|
|
84
|
+
for (const cmd of commands) {
|
|
85
|
+
await runCmd(cmd, projDir, deployId);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=cmd_executer.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cmd_executer.helper.js","sourceRoot":"","sources":["../../src/helpers/cmd_executer.helper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.helper.d.ts","sourceRoot":"","sources":["../../src/helpers/common.helper.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,MAe9C,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const normalizeRepoUrl = (url) => {
|
|
2
|
+
url = url.trim();
|
|
3
|
+
// already SSH
|
|
4
|
+
if (url.startsWith("git@"))
|
|
5
|
+
return url;
|
|
6
|
+
// HTTPS → SSH
|
|
7
|
+
if (url.startsWith("https://github.com/")) {
|
|
8
|
+
return url
|
|
9
|
+
.replace("https://github.com/", "git@github.com:")
|
|
10
|
+
.replace(/\.git$/, "") + ".git";
|
|
11
|
+
}
|
|
12
|
+
// fallback (leave as is)
|
|
13
|
+
return url;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=common.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.helper.js","sourceRoot":"","sources":["../../src/helpers/common.helper.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAW,EAAU,EAAE;IACtD,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAEjB,cAAc;IACd,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,GAAG,CAAC;IAEvC,cAAc;IACd,IAAI,GAAG,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,CAAC;QAC1C,OAAO,GAAG;aACP,OAAO,CAAC,qBAAqB,EAAE,iBAAiB,CAAC;aACjD,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC;IACpC,CAAC;IAED,yBAAyB;IACzB,OAAO,GAAG,CAAC;AACb,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config_files.helper.d.ts","sourceRoot":"","sources":["../../src/helpers/config_files.helper.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,wBAAwB,YA+CpC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { getPort, getWorkDirPath } from "./arg.helper.js";
|
|
4
|
+
export const createProxyAndLogConfigs = () => {
|
|
5
|
+
const dir = getWorkDirPath();
|
|
6
|
+
const port = getPort();
|
|
7
|
+
const nginxPath = path.join(dir, "nginx.conf");
|
|
8
|
+
const caddyPath = path.join(dir, "Caddyfile");
|
|
9
|
+
const logFile = path.join(dir, "vps-deployer.log");
|
|
10
|
+
// NGINX config
|
|
11
|
+
const nginxConfig = `
|
|
12
|
+
server {
|
|
13
|
+
listen 80;
|
|
14
|
+
server_name _;
|
|
15
|
+
|
|
16
|
+
location / {
|
|
17
|
+
proxy_pass http://127.0.0.1:${port};
|
|
18
|
+
proxy_http_version 1.1;
|
|
19
|
+
|
|
20
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
21
|
+
proxy_set_header Connection "upgrade";
|
|
22
|
+
proxy_set_header Host $host;
|
|
23
|
+
proxy_cache_bypass $http_upgrade;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
`.trim();
|
|
27
|
+
// Caddy config
|
|
28
|
+
const caddyConfig = `
|
|
29
|
+
:80 {
|
|
30
|
+
reverse_proxy 127.0.0.1:${port}
|
|
31
|
+
}
|
|
32
|
+
`.trim();
|
|
33
|
+
if (!fs.existsSync(nginxPath)) {
|
|
34
|
+
fs.writeFileSync(nginxPath, nginxConfig);
|
|
35
|
+
}
|
|
36
|
+
if (!fs.existsSync(caddyPath)) {
|
|
37
|
+
fs.writeFileSync(caddyPath, caddyConfig);
|
|
38
|
+
}
|
|
39
|
+
if (!fs.existsSync(logFile)) {
|
|
40
|
+
fs.writeFileSync(logFile, 'file created');
|
|
41
|
+
}
|
|
42
|
+
console.log('proxy config files created successfully');
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=config_files.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config_files.helper.js","sourceRoot":"","sources":["../../src/helpers/config_files.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE1D,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,EAAE;IAE3C,MAAM,GAAG,GAAI,cAAc,EAAE,CAAA;IAC7B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IAEtB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;IAEnD,eAAe;IACf,MAAM,WAAW,GAAG;;;;;;sCAMgB,IAAI;;;;;;;;;CASzC,CAAC,IAAI,EAAE,CAAC;IAEP,eAAe;IACf,MAAM,WAAW,GAAG;;8BAEQ,IAAI;;CAEjC,CAAC,IAAI,EAAE,CAAC;IAEP,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAA;AACxD,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type ServiceConfig = {
|
|
2
|
+
serviceName: string;
|
|
3
|
+
execPath: string;
|
|
4
|
+
args: string[];
|
|
5
|
+
workingDir: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const createSystemdService: ({ serviceName, execPath, args, workingDir, }: ServiceConfig) => void;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=create_systemd_service.helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_systemd_service.helper.d.ts","sourceRoot":"","sources":["../../src/helpers/create_systemd_service.helper.ts"],"names":[],"mappings":"AAIA,KAAK,aAAa,GAAG;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,8CAKlC,aAAa,SAyCf,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { writeToLogFile } from "./logging.helper.js";
|
|
4
|
+
export const createSystemdService = ({ serviceName, execPath, args, workingDir, }) => {
|
|
5
|
+
const serviceFilePath = `/etc/systemd/system/${serviceName}.service`;
|
|
6
|
+
const execCmd = [execPath, ...args, "--daemon"].join(" ");
|
|
7
|
+
const serviceContent = `
|
|
8
|
+
[Unit]
|
|
9
|
+
Description=VPS Deployer Service (${serviceName})
|
|
10
|
+
After=network.target
|
|
11
|
+
|
|
12
|
+
[Service]
|
|
13
|
+
Type=simple
|
|
14
|
+
ExecStart=${execCmd}
|
|
15
|
+
WorkingDirectory=${workingDir}
|
|
16
|
+
Restart=always
|
|
17
|
+
RestartSec=5
|
|
18
|
+
User=root
|
|
19
|
+
|
|
20
|
+
# logs go to journald
|
|
21
|
+
StandardOutput=journal
|
|
22
|
+
StandardError=journal
|
|
23
|
+
|
|
24
|
+
[Install]
|
|
25
|
+
WantedBy=multi-user.target
|
|
26
|
+
`;
|
|
27
|
+
try {
|
|
28
|
+
// 1. write service file
|
|
29
|
+
fs.writeFileSync(serviceFilePath, serviceContent.trim());
|
|
30
|
+
// 2. reload systemd
|
|
31
|
+
execSync("systemctl daemon-reexec");
|
|
32
|
+
execSync("systemctl daemon-reload");
|
|
33
|
+
writeToLogFile(`Service file created at ${serviceFilePath}. Run "vps-deployer start" to enable and start it.`, { level: "INFO", source: "SYS" });
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
writeToLogFile(`Systemd setup failed:${err.message}`, { level: "ERROR", source: "SYS" });
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=create_systemd_service.helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_systemd_service.helper.js","sourceRoot":"","sources":["../../src/helpers/create_systemd_service.helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AASrD,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,EACnC,WAAW,EACX,QAAQ,EACR,IAAI,EACJ,UAAU,GACI,EAAE,EAAE;IAClB,MAAM,eAAe,GAAG,uBAAuB,WAAW,UAAU,CAAC;IAErE,MAAM,OAAO,GAAG,CAAC,QAAQ,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE1D,MAAM,cAAc,GAAG;;oCAEW,WAAW;;;;;YAKnC,OAAO;mBACA,UAAU;;;;;;;;;;;CAW5B,CAAC;IAEA,IAAI,CAAC;QACH,wBAAwB;QACxB,EAAE,CAAC,aAAa,CAAC,eAAe,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;QAEzD,oBAAoB;QACpB,QAAQ,CAAC,yBAAyB,CAAC,CAAC;QACpC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;QAIpC,cAAc,CAAC,2BAA2B,eAAe,oDAAoD,EAAE,EAAC,KAAK,EAAC,MAAM,EAAE,MAAM,EAAC,KAAK,EAAC,CAAC,CAAC;IAC/I,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,cAAc,CAAC,wBAAwB,GAAG,CAAC,OAAO,EAAE,EAAC,EAAC,KAAK,EAAC,OAAO,EAAC,MAAM,EAAC,KAAK,EAAC,CAAC,CAAA;QAClF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC"}
|