ezpm2gui 1.6.0 → 1.8.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/README.md +330 -321
- package/bin/ezpm2gui.js +8 -8
- package/bin/ezpm2gui.ts +51 -51
- package/bin/generate-ecosystem.js +35 -35
- package/bin/generate-ecosystem.ts +56 -56
- package/dist/server/config/cron-jobs.json +1 -0
- package/dist/server/config/project-configs.json +235 -236
- package/dist/server/config/remote-connections.json +3 -0
- package/dist/server/index.js +42 -3
- package/dist/server/routes/deployApplication.js +47 -45
- package/dist/server/routes/logStreaming.js +31 -24
- package/dist/server/routes/modules.js +55 -0
- package/dist/server/routes/pageAuth.js +3 -3
- package/dist/server/routes/remoteConnections.js +13 -9
- package/dist/server/routes/remoteMetrics.d.ts +3 -0
- package/dist/server/routes/remoteMetrics.js +84 -0
- package/dist/server/services/ProjectSetupService.d.ts +1 -1
- package/dist/server/services/ProjectSetupService.js +25 -9
- package/dist/server/utils/metrics-history.d.ts +21 -0
- package/dist/server/utils/metrics-history.js +68 -0
- package/dist/server/utils/remote-metrics-db.d.ts +29 -0
- package/dist/server/utils/remote-metrics-db.js +134 -0
- package/dist/server/utils/remote-metrics-poller.d.ts +8 -0
- package/dist/server/utils/remote-metrics-poller.js +67 -0
- package/package.json +86 -73
- package/scripts/postinstall.js +36 -36
- package/src/client/build/asset-manifest.json +6 -6
- package/src/client/build/favicon.ico +2 -2
- package/src/client/build/index.html +1 -1
- package/src/client/build/logo192.svg +7 -7
- package/src/client/build/logo512.svg +7 -7
- package/src/client/build/manifest.json +24 -24
- package/src/client/build/static/css/main.9decb204.css +5 -0
- package/src/client/build/static/css/main.9decb204.css.map +1 -0
- package/src/client/build/static/js/main.28a4a583.js +3 -0
- package/src/client/build/static/js/main.28a4a583.js.map +1 -0
- package/src/client/build/static/css/main.775772ee.css +0 -5
- package/src/client/build/static/css/main.775772ee.css.map +0 -1
- package/src/client/build/static/js/main.cbcb09c9.js +0 -3
- package/src/client/build/static/js/main.cbcb09c9.js.map +0 -1
- /package/src/client/build/static/js/{main.cbcb09c9.js.LICENSE.txt → main.28a4a583.js.LICENSE.txt} +0 -0
|
@@ -1,236 +1,235 @@
|
|
|
1
|
-
{
|
|
2
|
-
"projectTypes": {
|
|
3
|
-
"node": {
|
|
4
|
-
"name": "Node.js",
|
|
5
|
-
"detection": {
|
|
6
|
-
"files": ["package.json"],
|
|
7
|
-
"extensions": [".js", ".ts", ".jsx", ".tsx"]
|
|
8
|
-
},
|
|
9
|
-
"setup": {
|
|
10
|
-
"steps": [
|
|
11
|
-
{
|
|
12
|
-
"name": "Check Node.js version",
|
|
13
|
-
"command": "node --version",
|
|
14
|
-
"description": "Verifying Node.js installation",
|
|
15
|
-
"required": true
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
"name": "Install dependencies",
|
|
19
|
-
"command": "npm install",
|
|
20
|
-
"description": "Installing project dependencies",
|
|
21
|
-
"required": true,
|
|
22
|
-
"workingDirectory": "project"
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
"name": "Build project (if build script exists)",
|
|
26
|
-
"command": "npm run build",
|
|
27
|
-
"description": "Building the project",
|
|
28
|
-
"required": false,
|
|
29
|
-
"conditional": "build_script_exists",
|
|
30
|
-
"workingDirectory": "project"
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
"name": "Run tests (if test script exists)",
|
|
34
|
-
"command": "npm test",
|
|
35
|
-
"description": "Running tests",
|
|
36
|
-
"required": false,
|
|
37
|
-
"conditional": "test_script_exists",
|
|
38
|
-
"workingDirectory": "project"
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
"environment": {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
"
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
"
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
"
|
|
155
|
-
|
|
156
|
-
"
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
"
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
"
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
"
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
"
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
"
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
"
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
"
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
"
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
"
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"projectTypes": {
|
|
3
|
+
"node": {
|
|
4
|
+
"name": "Node.js",
|
|
5
|
+
"detection": {
|
|
6
|
+
"files": ["package.json"],
|
|
7
|
+
"extensions": [".js", ".ts", ".jsx", ".tsx"]
|
|
8
|
+
},
|
|
9
|
+
"setup": {
|
|
10
|
+
"steps": [
|
|
11
|
+
{
|
|
12
|
+
"name": "Check Node.js version",
|
|
13
|
+
"command": "node --version",
|
|
14
|
+
"description": "Verifying Node.js installation",
|
|
15
|
+
"required": true
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "Install dependencies",
|
|
19
|
+
"command": "npm install",
|
|
20
|
+
"description": "Installing project dependencies",
|
|
21
|
+
"required": true,
|
|
22
|
+
"workingDirectory": "project"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "Build project (if build script exists)",
|
|
26
|
+
"command": "npm run build",
|
|
27
|
+
"description": "Building the project",
|
|
28
|
+
"required": false,
|
|
29
|
+
"conditional": "build_script_exists",
|
|
30
|
+
"workingDirectory": "project"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "Run tests (if test script exists)",
|
|
34
|
+
"command": "npm test",
|
|
35
|
+
"description": "Running tests",
|
|
36
|
+
"required": false,
|
|
37
|
+
"conditional": "test_script_exists",
|
|
38
|
+
"workingDirectory": "project"
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"environment": {}
|
|
42
|
+
},
|
|
43
|
+
"validation": {
|
|
44
|
+
"checks": [
|
|
45
|
+
{
|
|
46
|
+
"name": "package.json exists",
|
|
47
|
+
"file": "package.json"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "node_modules exists after install",
|
|
51
|
+
"directory": "node_modules",
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"defaultConfig": {
|
|
57
|
+
"interpreter": "node",
|
|
58
|
+
"execMode": "fork",
|
|
59
|
+
"supportsCluster": true,
|
|
60
|
+
"startScript": "npm start"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"python": {
|
|
64
|
+
"name": "Python",
|
|
65
|
+
"detection": {
|
|
66
|
+
"files": ["requirements.txt", "pyproject.toml", "setup.py", "Pipfile"],
|
|
67
|
+
"extensions": [".py"]
|
|
68
|
+
},
|
|
69
|
+
"setup": {
|
|
70
|
+
"steps": [
|
|
71
|
+
{
|
|
72
|
+
"name": "Check Python version",
|
|
73
|
+
"command": "python --version",
|
|
74
|
+
"description": "Verifying Python installation",
|
|
75
|
+
"required": true
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "Create virtual environment",
|
|
79
|
+
"command": "python -m venv venv",
|
|
80
|
+
"description": "Creating Python virtual environment",
|
|
81
|
+
"required": true,
|
|
82
|
+
"workingDirectory": "project"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "Activate virtual environment (Windows)",
|
|
86
|
+
"command": ".\\venv\\Scripts\\Activate.ps1",
|
|
87
|
+
"description": "Activating virtual environment",
|
|
88
|
+
"required": true,
|
|
89
|
+
"platform": "win32",
|
|
90
|
+
"workingDirectory": "project"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"name": "Activate virtual environment (Unix)",
|
|
94
|
+
"command": "source venv/bin/activate",
|
|
95
|
+
"description": "Activating virtual environment",
|
|
96
|
+
"required": true,
|
|
97
|
+
"platform": "unix",
|
|
98
|
+
"workingDirectory": "project"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "Upgrade pip",
|
|
102
|
+
"command": "python -m pip install --upgrade pip",
|
|
103
|
+
"description": "Upgrading pip",
|
|
104
|
+
"required": true,
|
|
105
|
+
"workingDirectory": "project",
|
|
106
|
+
"useVenv": true
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "Install requirements",
|
|
110
|
+
"command": "pip install -r requirements.txt",
|
|
111
|
+
"description": "Installing Python dependencies",
|
|
112
|
+
"required": true,
|
|
113
|
+
"conditional": "requirements_exists",
|
|
114
|
+
"workingDirectory": "project",
|
|
115
|
+
"useVenv": true
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "Install from pyproject.toml",
|
|
119
|
+
"command": "pip install -e .",
|
|
120
|
+
"description": "Installing from pyproject.toml",
|
|
121
|
+
"required": true,
|
|
122
|
+
"conditional": "pyproject_exists",
|
|
123
|
+
"workingDirectory": "project",
|
|
124
|
+
"useVenv": true
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
"environment": {
|
|
128
|
+
"PYTHONPATH": ".",
|
|
129
|
+
"PYTHON_UNBUFFERED": "1"
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"validation": {
|
|
133
|
+
"checks": [
|
|
134
|
+
{
|
|
135
|
+
"name": "Virtual environment created",
|
|
136
|
+
"directory": "venv"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "Requirements file exists",
|
|
140
|
+
"file": "requirements.txt",
|
|
141
|
+
"optional": true
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
},
|
|
145
|
+
"defaultConfig": {
|
|
146
|
+
"interpreter": "python",
|
|
147
|
+
"execMode": "fork",
|
|
148
|
+
"supportsCluster": false,
|
|
149
|
+
"interpreterPath": "venv/Scripts/python.exe"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"dotnet": {
|
|
153
|
+
"name": ".NET",
|
|
154
|
+
"detection": {
|
|
155
|
+
"files": ["*.csproj", "*.fsproj", "*.vbproj", "*.sln"],
|
|
156
|
+
"extensions": [".cs", ".fs", ".vb"]
|
|
157
|
+
},
|
|
158
|
+
"setup": {
|
|
159
|
+
"steps": [
|
|
160
|
+
{
|
|
161
|
+
"name": "Check .NET version",
|
|
162
|
+
"command": "dotnet --version",
|
|
163
|
+
"description": "Verifying .NET installation",
|
|
164
|
+
"required": true
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"name": "Restore packages",
|
|
168
|
+
"command": "dotnet restore",
|
|
169
|
+
"description": "Restoring NuGet packages",
|
|
170
|
+
"required": true,
|
|
171
|
+
"workingDirectory": "project"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"name": "Build project",
|
|
175
|
+
"command": "dotnet build --configuration Release",
|
|
176
|
+
"description": "Building .NET project",
|
|
177
|
+
"required": true,
|
|
178
|
+
"workingDirectory": "project"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"name": "Publish project",
|
|
182
|
+
"command": "dotnet publish --configuration Release --output ./publish",
|
|
183
|
+
"description": "Publishing .NET project",
|
|
184
|
+
"required": true,
|
|
185
|
+
"workingDirectory": "project"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"name": "Run tests",
|
|
189
|
+
"command": "dotnet test",
|
|
190
|
+
"description": "Running .NET tests",
|
|
191
|
+
"required": false,
|
|
192
|
+
"conditional": "test_project_exists",
|
|
193
|
+
"workingDirectory": "project"
|
|
194
|
+
}
|
|
195
|
+
],
|
|
196
|
+
"environment": {
|
|
197
|
+
"DOTNET_ENVIRONMENT": "Production",
|
|
198
|
+
"ASPNETCORE_ENVIRONMENT": "Production"
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"validation": {
|
|
202
|
+
"checks": [
|
|
203
|
+
{
|
|
204
|
+
"name": "Project file exists",
|
|
205
|
+
"pattern": "*.csproj"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"name": "Publish directory exists",
|
|
209
|
+
"directory": "publish"
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
},
|
|
213
|
+
"defaultConfig": {
|
|
214
|
+
"interpreter": "dotnet",
|
|
215
|
+
"execMode": "fork",
|
|
216
|
+
"supportsCluster": false,
|
|
217
|
+
"startCommand": "dotnet run"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"global": {
|
|
222
|
+
"timeouts": {
|
|
223
|
+
"setup": 300000,
|
|
224
|
+
"validation": 30000
|
|
225
|
+
},
|
|
226
|
+
"retries": {
|
|
227
|
+
"setup": 2,
|
|
228
|
+
"validation": 1
|
|
229
|
+
},
|
|
230
|
+
"logging": {
|
|
231
|
+
"level": "info",
|
|
232
|
+
"file": "deployment.log"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
package/dist/server/index.js
CHANGED
|
@@ -26,6 +26,9 @@ const pageAuth_1 = __importDefault(require("./routes/pageAuth"));
|
|
|
26
26
|
const logStreaming_1 = require("./routes/logStreaming");
|
|
27
27
|
const pm2_connection_1 = require("./utils/pm2-connection");
|
|
28
28
|
const remote_connection_1 = require("./utils/remote-connection");
|
|
29
|
+
const metrics_history_1 = require("./utils/metrics-history");
|
|
30
|
+
const remoteMetrics_1 = __importDefault(require("./routes/remoteMetrics"));
|
|
31
|
+
const remote_metrics_poller_1 = require("./utils/remote-metrics-poller");
|
|
29
32
|
/**
|
|
30
33
|
* Create and configure the express server
|
|
31
34
|
*/
|
|
@@ -68,6 +71,9 @@ function createServer() {
|
|
|
68
71
|
app.use('/api/cron-jobs', cronJobs_1.default);
|
|
69
72
|
app.use('/api/update', updates_1.default);
|
|
70
73
|
app.use('/api/auth', pageAuth_1.default);
|
|
74
|
+
app.use('/api/remote-metrics', remoteMetrics_1.default);
|
|
75
|
+
// Start remote metrics poller (30-second interval, polls all connected servers)
|
|
76
|
+
remote_metrics_poller_1.remoteMetricsPoller.start();
|
|
71
77
|
// Setup log streaming with Socket.IO
|
|
72
78
|
(0, logStreaming_1.setupLogStreaming)(io); // PM2 API endpoints
|
|
73
79
|
app.get('/api/processes', async (req, res) => {
|
|
@@ -137,6 +143,24 @@ function createServer() {
|
|
|
137
143
|
};
|
|
138
144
|
res.json(metrics);
|
|
139
145
|
});
|
|
146
|
+
// @group MetricsHistory : Return full history for all processes
|
|
147
|
+
app.get('/api/metrics/history', (_req, res) => {
|
|
148
|
+
res.json(metrics_history_1.metricsHistory.getAll());
|
|
149
|
+
});
|
|
150
|
+
// @group MetricsHistory : Return history for a single process by pm_id
|
|
151
|
+
app.get('/api/metrics/history/:processId', (req, res) => {
|
|
152
|
+
const pm_id = parseInt(req.params.processId, 10);
|
|
153
|
+
if (isNaN(pm_id)) {
|
|
154
|
+
res.status(400).json({ error: 'Invalid processId' });
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const entry = metrics_history_1.metricsHistory.getOne(pm_id);
|
|
158
|
+
if (!entry) {
|
|
159
|
+
res.status(404).json({ error: 'No history found for this process' });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
res.json(entry);
|
|
163
|
+
});
|
|
140
164
|
// @group LogHistory : Resolve log path from PM2 process descriptor
|
|
141
165
|
const resolveLocalLogPath = async (id, logType) => {
|
|
142
166
|
var _a, _b, _c;
|
|
@@ -355,6 +379,19 @@ function createServer() {
|
|
|
355
379
|
res.status(500).json({ error: 'Failed to download file' });
|
|
356
380
|
}
|
|
357
381
|
});
|
|
382
|
+
// @group MetricsHistory : Server-level polling — records PM2 process metrics into the history store
|
|
383
|
+
// This runs once regardless of how many clients are connected so the ring buffer fills consistently.
|
|
384
|
+
const historyPollInterval = setInterval(async () => {
|
|
385
|
+
try {
|
|
386
|
+
const processList = await (0, pm2_connection_1.executePM2Command)((callback) => {
|
|
387
|
+
pm2_1.default.list(callback);
|
|
388
|
+
});
|
|
389
|
+
metrics_history_1.metricsHistory.record(processList);
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
// silent — best-effort recording; don't crash the server
|
|
393
|
+
}
|
|
394
|
+
}, 3000);
|
|
358
395
|
// WebSocket for real-time updates
|
|
359
396
|
io.on('connection', (socket) => {
|
|
360
397
|
console.log('Client connected');
|
|
@@ -403,15 +440,17 @@ function createServer() {
|
|
|
403
440
|
res.status(404).send('File not found. Please check server configuration.');
|
|
404
441
|
}
|
|
405
442
|
});
|
|
443
|
+
// Clean up history poll on server close
|
|
444
|
+
server.on('close', () => clearInterval(historyPollInterval));
|
|
406
445
|
// Return the server instance
|
|
407
446
|
return server;
|
|
408
447
|
}
|
|
409
448
|
// Only start the server if this file is run directly
|
|
410
449
|
if (require.main === module) {
|
|
411
|
-
const PORT = process.env.PORT || 3101;
|
|
412
|
-
const HOST = process.env.HOST || '
|
|
450
|
+
const PORT = parseInt(process.env.PORT || '3101', 10);
|
|
451
|
+
const HOST = process.env.HOST || '::';
|
|
413
452
|
const server = createServer();
|
|
414
|
-
server.listen(PORT, () => {
|
|
453
|
+
server.listen(PORT, HOST, () => {
|
|
415
454
|
console.log(`Server running on http://${HOST}:${PORT}`);
|
|
416
455
|
});
|
|
417
456
|
// Handle shutdown gracefully
|