pm2-orbit 1.0.1
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 +220 -0
- package/bin/pm2-orbit.js +124 -0
- package/dist/server.js +1008 -0
- package/dist-ui/assets/charts-U3JqdBjU.js +3 -0
- package/dist-ui/assets/cmdk-D6Y8xHyf.js +49 -0
- package/dist-ui/assets/icons-DvbqpVzZ.js +234 -0
- package/dist-ui/assets/index-OYqKkh7V.css +1 -0
- package/dist-ui/assets/index-pRE_kpC2.js +56 -0
- package/dist-ui/assets/react-vendor-l0sNRNKZ.js +1 -0
- package/dist-ui/assets/table-virtual-Oq2FLz9e.js +30 -0
- package/dist-ui/favicon.svg +4 -0
- package/dist-ui/fonts/Exo-300.woff2 +0 -0
- package/dist-ui/fonts/Exo-400.woff2 +0 -0
- package/dist-ui/fonts/Exo-600.woff2 +0 -0
- package/dist-ui/fonts/JetBrainsMono-400.woff2 +0 -0
- package/dist-ui/index.html +62 -0
- package/package.json +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PM2 Orbit
|
|
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,220 @@
|
|
|
1
|
+
# PM2 Orbit
|
|
2
|
+
|
|
3
|
+
> High-performance, real-time PM2 monitoring dashboard. Event-driven architecture supporting 1000+ processes with zero configuration.
|
|
4
|
+
|
|
5
|
+
<!-- Add screenshot here:  -->
|
|
6
|
+
|
|
7
|
+
## Why PM2 Orbit?
|
|
8
|
+
|
|
9
|
+
Most PM2 dashboards poll the daemon every few hundred milliseconds, wasting resources and introducing latency. PM2 Orbit subscribes directly to PM2's event bus — updates arrive the instant they happen, with zero polling overhead.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx pm2-orbit
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
That's it. No config files, no databases, no Docker required. Opens in your browser and starts monitoring.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
**Process Monitoring**
|
|
22
|
+
- Real-time process status via WebSocket (online, stopped, errored, launching)
|
|
23
|
+
- Virtualized table handling 1000+ processes at 60fps
|
|
24
|
+
- Per-process CPU/memory sparklines with 120-point history
|
|
25
|
+
- Cluster mode support with per-worker breakdown
|
|
26
|
+
- One-click restart, stop, start, reload, delete for any process
|
|
27
|
+
- Bulk actions: Restart All, Stop All, Start All, Delete All
|
|
28
|
+
|
|
29
|
+
**Log Viewer**
|
|
30
|
+
- Live SSE log tailing from PM2's event bus
|
|
31
|
+
- ANSI escape code stripping for clean display
|
|
32
|
+
- Per-process or merged view with color coding
|
|
33
|
+
- Regex search with highlight
|
|
34
|
+
- Pause/resume without disconnecting
|
|
35
|
+
- Copy individual lines or download full buffer
|
|
36
|
+
|
|
37
|
+
**System Metrics**
|
|
38
|
+
- Host CPU, memory, load average, network I/O, disk I/O
|
|
39
|
+
- Auto-collecting via `systeminformation` with smart caching
|
|
40
|
+
- Historical charts with 1h / 6h / 24h time ranges
|
|
41
|
+
|
|
42
|
+
**Alert Engine**
|
|
43
|
+
- Rule-based alerts: CPU > N%, memory > NMB, restarts > N, process offline
|
|
44
|
+
- Multi-channel notifications: Slack, Discord, webhook, email, browser push
|
|
45
|
+
- Per-rule channel configuration with enable/disable toggles
|
|
46
|
+
- Cooldown to prevent alert fatigue
|
|
47
|
+
- Alert history with severity levels
|
|
48
|
+
|
|
49
|
+
**Developer Experience**
|
|
50
|
+
- Keyboard shortcuts: `R` restart, `S` stop, `End` scroll to bottom, `Ctrl+K` command palette
|
|
51
|
+
- Command palette for fuzzy process search and quick actions
|
|
52
|
+
- Dark / Light / System theme with smooth transitions
|
|
53
|
+
- Export/import settings as JSON
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# One command — installs pm2 automatically if missing
|
|
61
|
+
npm install -g pm2-orbit
|
|
62
|
+
pm2-orbit
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or run without installing:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx pm2-orbit
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## CLI Options
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
pm2-orbit [options]
|
|
77
|
+
|
|
78
|
+
Options:
|
|
79
|
+
-p, --port <port> Port to listen on (default: 9823)
|
|
80
|
+
-H, --host <host> Host to bind to (default: 127.0.0.1)
|
|
81
|
+
-t, --theme <theme> Theme: dark | light | system
|
|
82
|
+
-n, --no-open Don't open browser on start
|
|
83
|
+
-h, --help Show help
|
|
84
|
+
-v, --version Show version
|
|
85
|
+
|
|
86
|
+
Examples:
|
|
87
|
+
pm2-orbit # Start on default port
|
|
88
|
+
pm2-orbit -p 3000 # Start on port 3000
|
|
89
|
+
pm2-orbit --host 0.0.0.0 # Allow remote access
|
|
90
|
+
pm2-orbit --no-open # Don't open browser
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Environment Variables
|
|
96
|
+
|
|
97
|
+
| Variable | Description | Default |
|
|
98
|
+
|----------|-------------|---------|
|
|
99
|
+
| `PM2_ORBIT_PORT` | Server port | `9823` |
|
|
100
|
+
| `PM2_ORBIT_TOKEN` | Bearer auth token (required for non-localhost) | — |
|
|
101
|
+
| `PM2_ORBIT_LOG_BUFFER` | Max log lines per process | `2000` |
|
|
102
|
+
| `LOG_LEVEL` | Logger level: `debug`, `info`, `warn`, `error` | `info` |
|
|
103
|
+
| `CORS_ORIGINS` | Comma-separated allowed origins | `http://127.0.0.1:9823,http://localhost:9823` |
|
|
104
|
+
|
|
105
|
+
### Notification Channels
|
|
106
|
+
|
|
107
|
+
Notifications can be configured via environment variables **or** the Settings UI (accessible at `/settings` in the browser). The Settings UI saves to `~/.pm2-orbit/settings.json` and applies values at startup.
|
|
108
|
+
|
|
109
|
+
| Variable | Description |
|
|
110
|
+
|----------|-------------|
|
|
111
|
+
| `SLACK_WEBHOOK_URL` | Slack incoming webhook URL |
|
|
112
|
+
| `DISCORD_WEBHOOK_URL` | Discord webhook URL |
|
|
113
|
+
| `WEBHOOK_URL` | Generic POST webhook URL |
|
|
114
|
+
| `SMTP_HOST` | SMTP server hostname |
|
|
115
|
+
| `SMTP_PORT` | SMTP port (default: 587) |
|
|
116
|
+
| `SMTP_USER` | SMTP username |
|
|
117
|
+
| `SMTP_PASS` | SMTP password |
|
|
118
|
+
| `SMTP_FROM` | Sender email address |
|
|
119
|
+
| `SMTP_TO` | Recipient email address |
|
|
120
|
+
| `NOTIFY_*_ENABLED` | Set to `0` to disable a channel (e.g., `NOTIFY_SLACK_ENABLED=0`) |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Docker
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Build
|
|
128
|
+
docker build -t pm2-orbit .
|
|
129
|
+
|
|
130
|
+
# Run (mount PM2 socket for process access)
|
|
131
|
+
docker run -p 9823:9823 -v /run/pm2.sock:/run/pm2.sock pm2-orbit
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Development
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
git clone https://github.com/ihssmaheel-dev/pm2-orbit.git
|
|
140
|
+
cd pm2-orbit
|
|
141
|
+
npm install
|
|
142
|
+
npm run dev
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Starts Vite dev server on port 5151 with API proxy to the backend on port 9823.
|
|
146
|
+
|
|
147
|
+
### Scripts
|
|
148
|
+
|
|
149
|
+
| Command | Description |
|
|
150
|
+
|---------|-------------|
|
|
151
|
+
| `npm run dev` | Start dev mode (UI + server with hot reload) |
|
|
152
|
+
| `npm run build` | Build for production |
|
|
153
|
+
| `npm start` | Start production server |
|
|
154
|
+
| `npm run lint` | Type-check backend |
|
|
155
|
+
| `npm run typecheck` | Type-check both backend and frontend |
|
|
156
|
+
| `npm test` | Run tests |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Architecture
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
PM2 Daemon
|
|
164
|
+
│
|
|
165
|
+
│ pm2.launchBus() — event-driven, zero polling
|
|
166
|
+
▼
|
|
167
|
+
PM2 Bridge
|
|
168
|
+
│
|
|
169
|
+
├──► Event Pipeline (batched, debounced)
|
|
170
|
+
│
|
|
171
|
+
├──► Circular Buffer (120 points × typed arrays)
|
|
172
|
+
│
|
|
173
|
+
├──► Alert Engine (rule evaluation, per-process indexed)
|
|
174
|
+
│
|
|
175
|
+
├──► SQLite Store (optional, 24h retention)
|
|
176
|
+
│
|
|
177
|
+
└──► WebSocket Broadcaster
|
|
178
|
+
│
|
|
179
|
+
▼
|
|
180
|
+
React Frontend
|
|
181
|
+
│
|
|
182
|
+
├──► Zustand Store (single source of truth)
|
|
183
|
+
├──► Virtual Table (1000+ rows)
|
|
184
|
+
├──► Log Viewer (SSE + virtual scroll)
|
|
185
|
+
└──► Charts (uPlot, canvas-rendered)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Tech Stack
|
|
189
|
+
|
|
190
|
+
| Layer | Technology |
|
|
191
|
+
|-------|------------|
|
|
192
|
+
| **Runtime** | Node.js 18+ |
|
|
193
|
+
| **HTTP** | Fastify 5 |
|
|
194
|
+
| **WebSocket** | ws |
|
|
195
|
+
| **PM2 Integration** | `pm2.launchBus()` event subscription |
|
|
196
|
+
| **Metrics** | `systeminformation` |
|
|
197
|
+
| **Persistence** | better-sqlite3 (optional) |
|
|
198
|
+
| **Frontend** | React 19, Tailwind CSS, Zustand |
|
|
199
|
+
| **Virtualization** | TanStack Virtual |
|
|
200
|
+
| **Charts** | uPlot |
|
|
201
|
+
| **Build** | esbuild (backend), Vite (frontend) |
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Security
|
|
206
|
+
|
|
207
|
+
- Bearer token authentication via `PM2_ORBIT_TOKEN`
|
|
208
|
+
- CORS locked to localhost by default
|
|
209
|
+
- Rate limiting: 100 requests/minute per IP
|
|
210
|
+
- WebSocket connection limiting: 5 per IP
|
|
211
|
+
- Helmet security headers (XSS, CSP, HSTS)
|
|
212
|
+
- Environment variables masked in UI by default
|
|
213
|
+
- Process name sanitization in file paths
|
|
214
|
+
- Request ID tracking for audit trails
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
[MIT](LICENSE)
|
package/bin/pm2-orbit.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const mri = require('mri');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
const args = mri(process.argv.slice(2), {
|
|
9
|
+
alias: {
|
|
10
|
+
port: 'p',
|
|
11
|
+
theme: 't',
|
|
12
|
+
'no-open': 'n',
|
|
13
|
+
help: 'h',
|
|
14
|
+
version: 'v',
|
|
15
|
+
host: 'H',
|
|
16
|
+
},
|
|
17
|
+
default: {
|
|
18
|
+
port: parseInt(process.env.PM2_ORBIT_PORT || '9823', 10),
|
|
19
|
+
'no-open': false,
|
|
20
|
+
host: '127.0.0.1',
|
|
21
|
+
},
|
|
22
|
+
boolean: ['no-open', 'help', 'version'],
|
|
23
|
+
string: ['port', 'theme', 'host'],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
if (args.help) {
|
|
27
|
+
console.log(`
|
|
28
|
+
PM2 Orbit — High-performance PM2 monitoring dashboard
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
$ pm2-orbit [options]
|
|
32
|
+
|
|
33
|
+
Options:
|
|
34
|
+
--port, -p Port to listen on (default: 9823)
|
|
35
|
+
--host, -H Host to bind to (default: 127.0.0.1)
|
|
36
|
+
--no-open, -n Don't open browser automatically
|
|
37
|
+
--theme, -t Force theme (dark|light|system)
|
|
38
|
+
--help, -h Show this help
|
|
39
|
+
--version, -v Show version
|
|
40
|
+
|
|
41
|
+
Examples:
|
|
42
|
+
$ pm2-orbit # Start on default port
|
|
43
|
+
$ pm2-orbit -p 3000 # Start on port 3000
|
|
44
|
+
$ pm2-orbit --host 0.0.0.0 # Allow remote access
|
|
45
|
+
$ pm2-orbit --no-open # Don't open browser
|
|
46
|
+
`);
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (args.version) {
|
|
51
|
+
console.log(require('../package.json').version);
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check and auto-install pm2 if missing
|
|
56
|
+
function checkDependency(name, installCmd) {
|
|
57
|
+
try {
|
|
58
|
+
require.resolve(name);
|
|
59
|
+
return true;
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function installDependency(name, label) {
|
|
66
|
+
console.log(`\n \x1b[33m⚠\x1b[0m ${label} not found. Installing...`);
|
|
67
|
+
try {
|
|
68
|
+
const { execSync } = require('child_process');
|
|
69
|
+
execSync(`npm install -g ${name}`, { stdio: 'inherit', timeout: 120000 });
|
|
70
|
+
console.log(` \x1b[32m✓\x1b[0m ${label} installed successfully\n`);
|
|
71
|
+
return true;
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.error(` \x1b[31m✗\x1b[0m Failed to install ${label}: ${err.message}`);
|
|
74
|
+
console.log(` Please install manually: npm install -g ${name}\n`);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check dependencies
|
|
80
|
+
if (!checkDependency('pm2')) {
|
|
81
|
+
if (!installDependency('pm2', 'PM2')) {
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!checkDependency('better-sqlite3')) {
|
|
87
|
+
installDependency('better-sqlite3', 'better-sqlite3 (optional, for persistence)');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Set theme from CLI
|
|
91
|
+
if (args.theme) process.env.PM2_ORBIT_THEME = args.theme;
|
|
92
|
+
|
|
93
|
+
// Set host from CLI
|
|
94
|
+
if (args.host) process.env.PM2_ORBIT_HOST = args.host;
|
|
95
|
+
|
|
96
|
+
async function main() {
|
|
97
|
+
const pkg = require('../package.json');
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log(' \x1b[36mPM2 Orbit\x1b[0m v' + pkg.version);
|
|
100
|
+
console.log(' \x1b[90mHigh-performance PM2 monitoring dashboard\x1b[0m');
|
|
101
|
+
console.log('');
|
|
102
|
+
|
|
103
|
+
const { createServer } = require('../dist/server');
|
|
104
|
+
const server = await createServer({ port: args.port });
|
|
105
|
+
await server.listen({ port: args.port, host: args.host });
|
|
106
|
+
|
|
107
|
+
const url = `http://${args.host === '127.0.0.1' ? 'localhost' : args.host}:${args.port}`;
|
|
108
|
+
console.log(` \x1b[32m→\x1b[0m ${url}`);
|
|
109
|
+
console.log('');
|
|
110
|
+
|
|
111
|
+
if (!args['no-open']) {
|
|
112
|
+
try {
|
|
113
|
+
const { default: open } = await import('open');
|
|
114
|
+
await open(url);
|
|
115
|
+
} catch {
|
|
116
|
+
// open failed — non-critical
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
main().catch((err) => {
|
|
122
|
+
console.error('\n \x1b[31mPM2 Orbit failed to start:\x1b[0m', err.message);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
});
|