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.
Files changed (134) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/dist/app.d.ts +4 -0
  4. package/dist/app.d.ts.map +1 -0
  5. package/dist/app.js +39 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/db/db.d.ts +5 -0
  8. package/dist/db/db.d.ts.map +1 -0
  9. package/dist/db/db.js +100 -0
  10. package/dist/db/db.js.map +1 -0
  11. package/dist/helpers/arg.helper.d.ts +7 -0
  12. package/dist/helpers/arg.helper.d.ts.map +1 -0
  13. package/dist/helpers/arg.helper.js +28 -0
  14. package/dist/helpers/arg.helper.js.map +1 -0
  15. package/dist/helpers/cmd_executer.helper.d.ts +7 -0
  16. package/dist/helpers/cmd_executer.helper.d.ts.map +1 -0
  17. package/dist/helpers/cmd_executer.helper.js +88 -0
  18. package/dist/helpers/cmd_executer.helper.js.map +1 -0
  19. package/dist/helpers/common.helper.d.ts +2 -0
  20. package/dist/helpers/common.helper.d.ts.map +1 -0
  21. package/dist/helpers/common.helper.js +15 -0
  22. package/dist/helpers/common.helper.js.map +1 -0
  23. package/dist/helpers/config_files.helper.d.ts +2 -0
  24. package/dist/helpers/config_files.helper.d.ts.map +1 -0
  25. package/dist/helpers/config_files.helper.js +44 -0
  26. package/dist/helpers/config_files.helper.js.map +1 -0
  27. package/dist/helpers/create_systemd_service.helper.d.ts +9 -0
  28. package/dist/helpers/create_systemd_service.helper.d.ts.map +1 -0
  29. package/dist/helpers/create_systemd_service.helper.js +40 -0
  30. package/dist/helpers/create_systemd_service.helper.js.map +1 -0
  31. package/dist/helpers/date.helper.d.ts +2 -0
  32. package/dist/helpers/date.helper.d.ts.map +1 -0
  33. package/dist/helpers/date.helper.js +18 -0
  34. package/dist/helpers/date.helper.js.map +1 -0
  35. package/dist/helpers/email.helper.d.ts +11 -0
  36. package/dist/helpers/email.helper.d.ts.map +1 -0
  37. package/dist/helpers/email.helper.js +144 -0
  38. package/dist/helpers/email.helper.js.map +1 -0
  39. package/dist/helpers/logging.helper.d.ts +9 -0
  40. package/dist/helpers/logging.helper.d.ts.map +1 -0
  41. package/dist/helpers/logging.helper.js +32 -0
  42. package/dist/helpers/logging.helper.js.map +1 -0
  43. package/dist/helpers/remove_systemd_service.helper.d.ts +2 -0
  44. package/dist/helpers/remove_systemd_service.helper.d.ts.map +1 -0
  45. package/dist/helpers/remove_systemd_service.helper.js +21 -0
  46. package/dist/helpers/remove_systemd_service.helper.js.map +1 -0
  47. package/dist/helpers/start_systemd_service.helper.d.ts +2 -0
  48. package/dist/helpers/start_systemd_service.helper.d.ts.map +1 -0
  49. package/dist/helpers/start_systemd_service.helper.js +26 -0
  50. package/dist/helpers/start_systemd_service.helper.js.map +1 -0
  51. package/dist/index.d.ts +2 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +132 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/middleware/auth.middleware.d.ts +3 -0
  56. package/dist/middleware/auth.middleware.d.ts.map +1 -0
  57. package/dist/middleware/auth.middleware.js +7 -0
  58. package/dist/middleware/auth.middleware.js.map +1 -0
  59. package/dist/modules/auth/auth.route.d.ts +3 -0
  60. package/dist/modules/auth/auth.route.d.ts.map +1 -0
  61. package/dist/modules/auth/auth.route.js +16 -0
  62. package/dist/modules/auth/auth.route.js.map +1 -0
  63. package/dist/modules/auth/controllers/auth.controller.d.ts +6 -0
  64. package/dist/modules/auth/controllers/auth.controller.d.ts.map +1 -0
  65. package/dist/modules/auth/controllers/auth.controller.js +123 -0
  66. package/dist/modules/auth/controllers/auth.controller.js.map +1 -0
  67. package/dist/modules/auth/views/login.pug +254 -0
  68. package/dist/modules/auth/views/register.pug +298 -0
  69. package/dist/modules/common/views/404.pug +21 -0
  70. package/dist/modules/dashboard/dashboard.route.d.ts +3 -0
  71. package/dist/modules/dashboard/dashboard.route.d.ts.map +1 -0
  72. package/dist/modules/dashboard/dashboard.route.js +29 -0
  73. package/dist/modules/dashboard/dashboard.route.js.map +1 -0
  74. package/dist/modules/dashboard/views/dash.pug +149 -0
  75. package/dist/modules/dashboard/views/layout.pug +94 -0
  76. package/dist/modules/deployer/controllers/deployer.controller.d.ts +6 -0
  77. package/dist/modules/deployer/controllers/deployer.controller.d.ts.map +1 -0
  78. package/dist/modules/deployer/controllers/deployer.controller.js +119 -0
  79. package/dist/modules/deployer/controllers/deployer.controller.js.map +1 -0
  80. package/dist/modules/deployer/deployer.route.d.ts +3 -0
  81. package/dist/modules/deployer/deployer.route.d.ts.map +1 -0
  82. package/dist/modules/deployer/deployer.route.js +13 -0
  83. package/dist/modules/deployer/deployer.route.js.map +1 -0
  84. package/dist/modules/deployer/helper/deployer.d.ts +9 -0
  85. package/dist/modules/deployer/helper/deployer.d.ts.map +1 -0
  86. package/dist/modules/deployer/helper/deployer.js +89 -0
  87. package/dist/modules/deployer/helper/deployer.js.map +1 -0
  88. package/dist/modules/deployer/views/details.pug +157 -0
  89. package/dist/modules/deployer/views/index.pug +108 -0
  90. package/dist/modules/project/controllers/projects.controller.d.ts +12 -0
  91. package/dist/modules/project/controllers/projects.controller.d.ts.map +1 -0
  92. package/dist/modules/project/controllers/projects.controller.js +267 -0
  93. package/dist/modules/project/controllers/projects.controller.js.map +1 -0
  94. package/dist/modules/project/helper/project_file_sys.helper.d.ts +7 -0
  95. package/dist/modules/project/helper/project_file_sys.helper.d.ts.map +1 -0
  96. package/dist/modules/project/helper/project_file_sys.helper.js +93 -0
  97. package/dist/modules/project/helper/project_file_sys.helper.js.map +1 -0
  98. package/dist/modules/project/project.route.d.ts +3 -0
  99. package/dist/modules/project/project.route.d.ts.map +1 -0
  100. package/dist/modules/project/project.route.js +17 -0
  101. package/dist/modules/project/project.route.js.map +1 -0
  102. package/dist/modules/project/views/create.pug +189 -0
  103. package/dist/modules/project/views/details.pug +238 -0
  104. package/dist/modules/project/views/index.pug +114 -0
  105. package/dist/modules/settings/controllers/setting.controller.d.ts +5 -0
  106. package/dist/modules/settings/controllers/setting.controller.d.ts.map +1 -0
  107. package/dist/modules/settings/controllers/setting.controller.js +193 -0
  108. package/dist/modules/settings/controllers/setting.controller.js.map +1 -0
  109. package/dist/modules/settings/settings.route.d.ts +3 -0
  110. package/dist/modules/settings/settings.route.d.ts.map +1 -0
  111. package/dist/modules/settings/settings.route.js +10 -0
  112. package/dist/modules/settings/settings.route.js.map +1 -0
  113. package/dist/modules/settings/views/index.pug +173 -0
  114. package/dist/modules/webhook/controllers/webhook.controller.d.ts +3 -0
  115. package/dist/modules/webhook/controllers/webhook.controller.d.ts.map +1 -0
  116. package/dist/modules/webhook/controllers/webhook.controller.js +72 -0
  117. package/dist/modules/webhook/controllers/webhook.controller.js.map +1 -0
  118. package/dist/modules/webhook/webhook.route.d.ts +3 -0
  119. package/dist/modules/webhook/webhook.route.d.ts.map +1 -0
  120. package/dist/modules/webhook/webhook.route.js +6 -0
  121. package/dist/modules/webhook/webhook.route.js.map +1 -0
  122. package/dist/utils/app_config.d.ts +3 -0
  123. package/dist/utils/app_config.d.ts.map +1 -0
  124. package/dist/utils/app_config.js +5 -0
  125. package/dist/utils/app_config.js.map +1 -0
  126. package/dist/utils/cli.d.ts +2 -0
  127. package/dist/utils/cli.d.ts.map +1 -0
  128. package/dist/utils/cli.js +68 -0
  129. package/dist/utils/cli.js.map +1 -0
  130. package/package.json +80 -0
  131. package/public/favicon.svg +18 -0
  132. package/public/js/deploy.js +36 -0
  133. package/public/js/deployment-details.js +56 -0
  134. package/public/js/login.js +21 -0
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
3
+ //# sourceMappingURL=dashboard.route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.route.d.ts","sourceRoot":"","sources":["../../../src/modules/dashboard/dashboard.route.ts"],"names":[],"mappings":"AAGA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAkCxB,eAAe,MAAM,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { Router } from "express";
2
+ import { getDB } from "../../db/db.js";
3
+ const router = Router();
4
+ router.get("/", (req, res) => {
5
+ if (!req.session || !req.session.user) {
6
+ return res.redirect("/login");
7
+ }
8
+ const db = getDB();
9
+ const stats = {
10
+ projects: db.prepare(`SELECT COUNT(*) as count FROM project`).get().count,
11
+ deployments: db.prepare(`SELECT COUNT(*) as count FROM deployment`).get().count,
12
+ running: db.prepare(`SELECT COUNT(*) as count FROM deployment WHERE status='running'`).get().count,
13
+ failed: db.prepare(`SELECT COUNT(*) as count FROM deployment WHERE status='failed'`).get().count,
14
+ };
15
+ const recentDeployments = db.prepare(`
16
+ SELECT d.id, d.status, d.started_at, p.name
17
+ FROM deployment d
18
+ JOIN project p ON d.proj_id = p.id
19
+ ORDER BY d.started_at DESC
20
+ LIMIT 5
21
+ `).all();
22
+ return res.render("dashboard/views/dash", {
23
+ active: "home",
24
+ stats,
25
+ recentDeployments,
26
+ });
27
+ });
28
+ export default router;
29
+ //# sourceMappingURL=dashboard.route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.route.js","sourceRoot":"","sources":["../../../src/modules/dashboard/dashboard.route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IAC9C,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACtC,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;IAEnB,MAAM,KAAK,GAAG;QACd,QAAQ,EAAG,EAAE,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,EAAwB,CAAC,KAAK;QAEhG,WAAW,EAAG,EAAE,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC,GAAG,EAAwB,CAAC,KAAK;QAEtG,OAAO,EAAG,EAAE,CAAC,OAAO,CAAC,iEAAiE,CAAC,CAAC,GAAG,EAAwB,CAAC,KAAK;QAEzH,MAAM,EAAG,EAAE,CAAC,OAAO,CAAC,gEAAgE,CAAC,CAAC,GAAG,EAAwB,CAAC,KAAK;KACxH,CAAC;IAEA,MAAM,iBAAiB,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;GAMpC,CAAC,CAAC,GAAG,EAAE,CAAC;IAET,OAAO,GAAG,CAAC,MAAM,CAAC,sBAAsB,EAAE;QACxC,MAAM,EAAE,MAAM;QACd,KAAK;QACL,iBAAiB;KAClB,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,149 @@
1
+ extends ./layout.pug
2
+
3
+ block content
4
+ // Page Header
5
+ .d-flex.justify-content-between.align-items-center.mb-4
6
+ div
7
+ h2.mb-1 Dashboard
8
+ p.text-muted.mb-0 Welcome back to VPS Deployer
9
+ div
10
+ i.bi.bi-grid-3x3-gap-fill.text-muted(style="font-size: 1.5rem;")
11
+
12
+ // ===== STATS CARDS =====
13
+ .row.mb-4.g-3
14
+ .col-md-3
15
+ .card.border-0.shadow-sm.h-100
16
+ .card-body
17
+ .d-flex.justify-content-between.align-items-start
18
+ div
19
+ p.text-muted.mb-1.small.text-uppercase.fw-semibold Projects
20
+ h2.mb-0.fw-bold #{stats.projects}
21
+ .bg-light.rounded-circle.p-3
22
+ i.bi.bi-folder.text-primary(style="font-size: 1.25rem;")
23
+
24
+ .col-md-3
25
+ .card.border-0.shadow-sm.h-100
26
+ .card-body
27
+ .d-flex.justify-content-between.align-items-start
28
+ div
29
+ p.text-muted.mb-1.small.text-uppercase.fw-semibold Deployments
30
+ h2.mb-0.fw-bold #{stats.deployments}
31
+ .bg-light.rounded-circle.p-3
32
+ i.bi.bi-rocket-takeoff.text-primary(style="font-size: 1.25rem;")
33
+
34
+ .col-md-3
35
+ .card.border-0.shadow-sm.h-100
36
+ .card-body
37
+ .d-flex.justify-content-between.align-items-start
38
+ div
39
+ p.text-muted.mb-1.small.text-uppercase.fw-semibold Running
40
+ h2.mb-0.fw-bold.text-warning #{stats.running}
41
+ .bg-light.rounded-circle.p-3
42
+ i.bi.bi-play-circle.text-warning(style="font-size: 1.25rem;")
43
+
44
+ .col-md-3
45
+ .card.border-0.shadow-sm.h-100
46
+ .card-body
47
+ .d-flex.justify-content-between.align-items-start
48
+ div
49
+ p.text-muted.mb-1.small.text-uppercase.fw-semibold Failed
50
+ h2.mb-0.fw-bold.text-danger #{stats.failed}
51
+ .bg-light.rounded-circle.p-3
52
+ i.bi.bi-x-circle.text-danger(style="font-size: 1.25rem;")
53
+
54
+ // ===== QUICK ACTIONS =====
55
+ .card.border-0.shadow-sm.mb-4
56
+ .card-body
57
+ .d-flex.justify-content-between.align-items-center
58
+ div
59
+ h5.mb-1 Quick Actions
60
+ p.text-muted.mb-0.small Deploy, manage, and monitor your projects
61
+ div
62
+ a.btn.btn-primary.me-2(href="/projects")
63
+ i.bi.bi-folder-plus.me-2
64
+ | Manage Projects
65
+ a.btn.btn-outline-dark(href="/deployments")
66
+ i.bi.bi-clock-history.me-2
67
+ | View Deployments
68
+
69
+ // ===== RECENT DEPLOYMENTS =====
70
+ .card.border-0.shadow-sm
71
+ .card-header.bg-white.border-bottom-0.pt-3
72
+ .d-flex.justify-content-between.align-items-center
73
+ div
74
+ h5.mb-0 Recent Deployments
75
+ p.text-muted.small.mb-0 Latest deployment activity
76
+ if recentDeployments.length > 0
77
+ a.btn.btn-sm.btn-link.text-decoration-none(href="/deployments") View all →
78
+
79
+ .card-body
80
+ if recentDeployments.length === 0
81
+ .text-center.py-5
82
+ i.bi.bi-inbox.display-1.text-muted
83
+ p.text-muted.mt-3.mb-0 No deployments yet
84
+ a.btn.btn-sm.btn-primary.mt-3(href="/projects") Create your first project
85
+ else
86
+ .table-responsive
87
+ table.table.table-hover.align-middle.mb-0
88
+ thead.table-light
89
+ tr
90
+ th(style="font-weight: 600;") Project Name
91
+ th(style="font-weight: 600;") Status
92
+ th(style="font-weight: 600;") Started
93
+ th(style="font-weight: 600;") Action
94
+ tbody
95
+ each d in recentDeployments
96
+ tr
97
+ td
98
+ .d-flex.align-items-center
99
+ i.bi.bi-folder-fill.text-primary.me-2
100
+ span.fw-medium #{d.name}
101
+ td
102
+ if d.status === "running"
103
+ span.badge.bg-warning.text-dark.px-3.py-2
104
+ i.bi.bi-play-fill.me-1
105
+ | running
106
+ else if d.status === "success"
107
+ span.badge.bg-success.px-3.py-2
108
+ i.bi.bi-check-circle-fill.me-1
109
+ | success
110
+ else
111
+ span.badge.bg-danger.px-3.py-2
112
+ i.bi.bi-x-circle-fill.me-1
113
+ | failed
114
+ td
115
+ .d-flex.align-items-center
116
+ i.bi.bi-clock.text-muted.me-2
117
+ small.text-muted #{d.started_at}
118
+ td
119
+ a.btn.btn-sm.btn-outline-primary(href=`/deployment/${d.id}`)
120
+ i.bi.bi-eye.me-1
121
+ | View
122
+
123
+ // Additional styles
124
+ style.
125
+ .card {
126
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
127
+ }
128
+
129
+ .card:hover {
130
+ transform: translateY(-2px);
131
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.08) !important;
132
+ }
133
+
134
+ .table-hover tbody tr:hover {
135
+ background-color: #f8f9fa;
136
+ }
137
+
138
+ .badge {
139
+ font-weight: 500;
140
+ font-size: 0.75rem;
141
+ }
142
+
143
+ .btn-link {
144
+ color: #0066ff;
145
+ }
146
+
147
+ .btn-link:hover {
148
+ color: #0052cc;
149
+ }
@@ -0,0 +1,94 @@
1
+ doctype html
2
+ html
3
+ head
4
+ title VPS Deployer
5
+ meta(charset="UTF-8")
6
+ meta(name="viewport", content="width=device-width, initial-scale=1")
7
+
8
+ link(
9
+ href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css",
10
+ rel="stylesheet"
11
+ )
12
+ link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css")
13
+ link(rel="icon", type="image/svg+xml", href="/favicon.svg")
14
+
15
+ style.
16
+ body {
17
+ background: #f5f7fa;
18
+ }
19
+
20
+ .navbar {
21
+ background: #1a1f36 !important;
22
+ border-bottom: 1px solid #e9ecef;
23
+ }
24
+
25
+ .navbar-brand {
26
+ font-weight: 600;
27
+ color: #ffffff !important;
28
+ }
29
+
30
+ .nav-link {
31
+ color: #e0e0e0 !important;
32
+ }
33
+
34
+ .nav-link:hover {
35
+ color: #ffffff !important;
36
+ }
37
+
38
+ .nav-link.active {
39
+ color: #ffffff !important;
40
+ font-weight: 500;
41
+ }
42
+
43
+ footer {
44
+ background: #ffffff;
45
+ border-top: 1px solid #e9ecef;
46
+ color: #6c757d;
47
+ font-size: 0.875rem;
48
+ }
49
+
50
+ .footer-link {
51
+ color: #0066ff;
52
+ text-decoration: none;
53
+ }
54
+
55
+ .footer-link:hover {
56
+ text-decoration: underline;
57
+ }
58
+
59
+ body.d-flex.flex-column.min-vh-100
60
+
61
+ // Navbar
62
+ nav.navbar.navbar-expand-lg.navbar-dark.bg-dark
63
+ .container
64
+ a.navbar-brand(href="/")
65
+ i.bi.bi-cloud-check.me-2
66
+ | VPS Deployer
67
+
68
+ button.navbar-toggler(type="button", data-bs-toggle="collapse", data-bs-target="#nav")
69
+ span.navbar-toggler-icon
70
+
71
+ .collapse.navbar-collapse#nav
72
+ ul.navbar-nav.ms-auto
73
+ li.nav-item
74
+ a.nav-link(class=(active === "home" ? "active" : ""), href="/") Home
75
+ li.nav-item
76
+ a.nav-link(class=(active === "project" ? "active" : ""), href="/projects") Projects
77
+ li.nav-item
78
+ a.nav-link(class=(active === "deployments" ? "active" : ""), href="/deployments") Deployments
79
+ li.nav-item
80
+ a.nav-link(class=(active === "settings" ? "active" : ""), href="/settings") Settings
81
+
82
+ // Main content
83
+ main.container.my-4.flex-grow-1
84
+ block content
85
+
86
+ // Footer
87
+ footer.text-center.py-3.mt-auto
88
+ .container
89
+ span Made with
90
+ i.bi.bi-suit-heart-fill.text-danger
91
+ | for the OSS community by
92
+ a.footer-link(href="https://github.com/0xv1shal", target="_blank") 0xv1shal
93
+
94
+ script(src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js")
@@ -0,0 +1,6 @@
1
+ import { type Request, type Response } from "express";
2
+ export declare const createDeployment: (req: Request, res: Response) => Response<any, Record<string, any>>;
3
+ export declare const getDeploymentDetails: (req: Request, res: Response) => Response<any, Record<string, any>>;
4
+ export declare const getDeploymentDetailsView: (req: Request, res: Response) => void;
5
+ export declare const getDeploymentView: (_req: Request, res: Response) => void;
6
+ //# sourceMappingURL=deployer.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployer.controller.d.ts","sourceRoot":"","sources":["../../../../src/modules/deployer/controllers/deployer.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAItD,eAAO,MAAM,gBAAgB,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,uCAuD3D,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,uCAwC/D,CAAC;AAEF,eAAO,MAAM,wBAAwB,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,SAoCnE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,MAAM,OAAO,EAAE,KAAK,QAAQ,SAkB7D,CAAC"}
@@ -0,0 +1,119 @@
1
+ import {} from "express";
2
+ import { getDB } from "../../../db/db.js";
3
+ import { triggerDeployment } from "../helper/deployer.js";
4
+ export const createDeployment = (req, res) => {
5
+ const { projId } = req.body;
6
+ if (!projId || typeof projId !== "string" || projId.trim() === "") {
7
+ return res.status(400).json({ message: "projId is invalid" });
8
+ }
9
+ const db = getDB();
10
+ const project = db
11
+ .prepare(`SELECT id FROM project WHERE id = ?`)
12
+ .get(projId);
13
+ if (!project) {
14
+ return res.status(404).json({ message: "project not found" });
15
+ }
16
+ // fetch commands (ordered)
17
+ const commands = db
18
+ .prepare(`
19
+ SELECT cmd
20
+ FROM project_commands
21
+ WHERE proj_id = ?
22
+ ORDER BY seq_no ASC
23
+ `)
24
+ .all(projId).map((row) => row.cmd);
25
+ if (commands.length === 0) {
26
+ return res.status(400).json({
27
+ message: "No commands configured for this project",
28
+ });
29
+ }
30
+ // generate deployment id
31
+ const deployId = crypto.randomUUID();
32
+ // create deployment row
33
+ db.prepare(`
34
+ INSERT INTO deployment (id, proj_id, status)
35
+ VALUES (?, ?, 'running')
36
+ `).run(deployId, projId);
37
+ // enqueue (non-blocking)
38
+ triggerDeployment(deployId, projId, commands);
39
+ return res.json({
40
+ message: "deployment queued",
41
+ deployId,
42
+ });
43
+ };
44
+ export const getDeploymentDetails = (req, res) => {
45
+ const { deployId } = req.params;
46
+ if (!deployId) {
47
+ return res.status(400).json({ message: "deployId required" });
48
+ }
49
+ const db = getDB();
50
+ const deployment = db
51
+ .prepare(`
52
+ SELECT d.id, d.proj_id, d.status, d.started_at, d.finished_at,
53
+ p.name, p.github_url, p.branch_name
54
+ FROM deployment d
55
+ JOIN project p ON d.proj_id = p.id
56
+ WHERE d.id = ?
57
+ `)
58
+ .get(deployId);
59
+ if (!deployment) {
60
+ return res.status(404).json({ message: "deployment not found" });
61
+ }
62
+ const logs = db
63
+ .prepare(`
64
+ SELECT id, cmd, log, status, started_at, finished_at
65
+ FROM deployment_logs
66
+ WHERE deploy_id = ?
67
+ ORDER BY started_at ASC
68
+ `)
69
+ .all(deployId);
70
+ return res.json({
71
+ deployment,
72
+ logs,
73
+ });
74
+ };
75
+ export const getDeploymentDetailsView = (req, res) => {
76
+ const { deployId } = req.params;
77
+ const db = getDB();
78
+ const deployment = db
79
+ .prepare(`
80
+ SELECT d.id, d.proj_id, d.status, d.started_at, d.finished_at,
81
+ p.name, p.github_url, p.branch_name
82
+ FROM deployment d
83
+ JOIN project p ON d.proj_id = p.id
84
+ WHERE d.id = ?
85
+ `)
86
+ .get(deployId);
87
+ if (!deployment) {
88
+ return res.status(404).render("common/views/404");
89
+ }
90
+ const logs = db
91
+ .prepare(`
92
+ SELECT id, cmd, log, status, started_at, finished_at
93
+ FROM deployment_logs
94
+ WHERE deploy_id = ?
95
+ ORDER BY started_at ASC
96
+ `)
97
+ .all(deployId);
98
+ return res.render("deployer/views/details", {
99
+ deployment,
100
+ logs,
101
+ active: "deployments",
102
+ });
103
+ };
104
+ export const getDeploymentView = (_req, res) => {
105
+ const db = getDB();
106
+ const deployments = db
107
+ .prepare(`
108
+ SELECT d.*, p.name
109
+ FROM deployment d
110
+ JOIN project p ON d.proj_id = p.id
111
+ ORDER BY d.started_at DESC
112
+ `)
113
+ .all();
114
+ return res.render("deployer/views/index", {
115
+ deployments,
116
+ active: "deployments",
117
+ });
118
+ };
119
+ //# sourceMappingURL=deployer.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployer.controller.js","sourceRoot":"","sources":["../../../../src/modules/deployer/controllers/deployer.controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const router: import("express-serve-static-core").Router;
2
+ export default router;
3
+ //# sourceMappingURL=deployer.route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployer.route.d.ts","sourceRoot":"","sources":["../../../src/modules/deployer/deployer.route.ts"],"names":[],"mappings":"AAIA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAWxB,eAAe,MAAM,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { Router } from "express";
2
+ import { createDeployment, getDeploymentDetails, getDeploymentDetailsView, getDeploymentView } from "./controllers/deployer.controller.js";
3
+ import { requireAuth } from "../../middleware/auth.middleware.js";
4
+ const router = Router();
5
+ router.use(requireAuth);
6
+ // API (used by frontend JS)
7
+ router.post("/deploy", createDeployment);
8
+ router.get("/deploy/:deployId", getDeploymentDetails);
9
+ // Views (page navigation only)
10
+ router.get("/deployments", getDeploymentView);
11
+ router.get("/deployment/:deployId", getDeploymentDetailsView);
12
+ export default router;
13
+ //# sourceMappingURL=deployer.route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployer.route.js","sourceRoot":"","sources":["../../../src/modules/deployer/deployer.route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC3I,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAElE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;AAExB,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;AACvB,4BAA4B;AAC5B,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AACzC,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,oBAAoB,CAAC,CAAC;AAEtD,+BAA+B;AAC/B,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;AAC9C,MAAM,CAAC,GAAG,CAAC,uBAAuB,EAAE,wBAAwB,CAAC,CAAC;AAE9D,eAAe,MAAM,CAAC"}
@@ -0,0 +1,9 @@
1
+ type DeploymentJob = {
2
+ deployId: string;
3
+ run: () => Promise<void>;
4
+ };
5
+ export declare const enqueueDeployment: (job: DeploymentJob) => void;
6
+ export declare const runDeployment: (deployId: string, projId: string, commands: string[]) => Promise<void>;
7
+ export declare const triggerDeployment: (deployId: string, projId: string, cmds: string[]) => void;
8
+ export {};
9
+ //# sourceMappingURL=deployer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployer.d.ts","sourceRoot":"","sources":["../../../../src/modules/deployer/helper/deployer.ts"],"names":[],"mappings":"AAMA,KAAK,aAAa,GAAG;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B,CAAC;AASF,eAAO,MAAM,iBAAiB,GAAI,KAAK,aAAa,SAGnD,CAAC;AAwBF,eAAO,MAAM,aAAa,GACxB,UAAU,MAAM,EAChB,QAAQ,MAAM,EACd,UAAU,MAAM,EAAE,kBAgBnB,CAAC;AAMF,eAAO,MAAM,iBAAiB,GAC5B,UAAU,MAAM,EAChB,QAAQ,MAAM,EACd,MAAM,MAAM,EAAE,SAQf,CAAC"}
@@ -0,0 +1,89 @@
1
+ import path from "path";
2
+ import { getDB } from "../../../db/db.js";
3
+ import { getWorkDirPath } from "../../../helpers/arg.helper.js";
4
+ import { runCmdSeq } from "../../../helpers/cmd_executer.helper.js";
5
+ import { sendDeploymentResultEmail } from "../../../helpers/email.helper.js";
6
+ /* =========================
7
+ IN-MEM QUEUE (FIFO, 1 worker)
8
+ ========================= */
9
+ const queue = [];
10
+ let isRunning = false;
11
+ export const enqueueDeployment = (job) => {
12
+ queue.push(job);
13
+ processQueue();
14
+ };
15
+ const processQueue = async () => {
16
+ if (isRunning)
17
+ return;
18
+ if (queue.length === 0)
19
+ return;
20
+ isRunning = true;
21
+ const job = queue.shift();
22
+ if (!job) {
23
+ isRunning = false;
24
+ return;
25
+ }
26
+ try {
27
+ await job.run();
28
+ }
29
+ catch (err) {
30
+ // deployment handles its own failure logging
31
+ }
32
+ finally {
33
+ isRunning = false;
34
+ processQueue(); // next job
35
+ }
36
+ };
37
+ export const runDeployment = async (deployId, projId, commands) => {
38
+ try {
39
+ markDeploymentRunning(deployId);
40
+ const projDir = path.join(getWorkDirPath(), projId);
41
+ await runCmdSeq(commands, projDir, deployId);
42
+ markDeploymentSuccess(deployId);
43
+ await sendDeploymentResultEmail(deployId, "success");
44
+ }
45
+ catch (err) {
46
+ markDeploymentFailed(deployId);
47
+ await sendDeploymentResultEmail(deployId, "failed");
48
+ }
49
+ };
50
+ /* =========================
51
+ PUBLIC API (ENTRY POINT)
52
+ ========================= */
53
+ export const triggerDeployment = (deployId, projId, cmds) => {
54
+ enqueueDeployment({
55
+ deployId,
56
+ run: async () => {
57
+ await runDeployment(deployId, projId, cmds);
58
+ },
59
+ });
60
+ };
61
+ const markDeploymentRunning = async (deployId) => {
62
+ const db = getDB();
63
+ db.prepare(`
64
+ UPDATE deployment
65
+ SET status = 'running',
66
+ started_at = datetime('now'),
67
+ finished_at = NULL
68
+ WHERE id = ?
69
+ `).run(deployId);
70
+ };
71
+ const markDeploymentSuccess = async (deployId) => {
72
+ const db = getDB();
73
+ db.prepare(`
74
+ UPDATE deployment
75
+ SET status = 'success',
76
+ finished_at = datetime('now')
77
+ WHERE id = ?
78
+ `).run(deployId);
79
+ };
80
+ const markDeploymentFailed = async (deployId) => {
81
+ const db = getDB();
82
+ db.prepare(`
83
+ UPDATE deployment
84
+ SET status = 'failed',
85
+ finished_at = datetime('now')
86
+ WHERE id = ?
87
+ `).run(deployId);
88
+ };
89
+ //# sourceMappingURL=deployer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployer.js","sourceRoot":"","sources":["../../../../src/modules/deployer/helper/deployer.ts"],"names":[],"mappings":"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"}