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 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: ![Dashboard](screenshot.png) -->
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)
@@ -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
+ });