bm2 1.0.34 → 1.0.36
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 +145 -12
- package/package.json +1 -1
- package/src/daemon-v1.ts +244 -0
- package/src/daemon.ts +238 -195
- package/src/index.ts +862 -797
- package/src/types.ts +1 -0
- package/src/utils.ts +7 -7
package/README.md
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
# ⚡ BM2
|
|
3
2
|
|
|
4
3
|
**A blazing-fast, full-featured process manager built entirely on Bun native APIs.**
|
|
@@ -34,6 +33,7 @@ The modern PM2 replacement — zero Node.js dependencies, pure Bun performance.
|
|
|
34
33
|
- [Startup Scripts](#startup-scripts)
|
|
35
34
|
- [Modules](#modules)
|
|
36
35
|
- [Daemon Control](#daemon-control)
|
|
36
|
+
- [Foreground Mode (Docker & Containers)](#foreground-mode-docker--containers)
|
|
37
37
|
- [Configuration Reference](#configuration-reference)
|
|
38
38
|
- [Ecosystem File Format](#ecosystem-file-format)
|
|
39
39
|
- [Process Options](#process-options)
|
|
@@ -88,6 +88,8 @@ BM2 replaces PM2's Node.js internals with Bun-native APIs. It uses `Bun.spawn` f
|
|
|
88
88
|
|
|
89
89
|
**Zero-Downtime Reload** — Graceful reload cycles through instances sequentially, starting the new process before stopping the old one, ensuring your application never drops a request.
|
|
90
90
|
|
|
91
|
+
**Foreground / No-Daemon Mode** — Run BM2 in blocking foreground mode without spawning a background daemon. Designed for containerized environments like Docker, Kubernetes, and any platform that expects PID 1 to remain in the foreground.
|
|
92
|
+
|
|
91
93
|
**Real-Time Web Dashboard** — A built-in dark-themed web dashboard with live WebSocket updates, CPU/memory charts, process control buttons, and a log viewer. No external dependencies.
|
|
92
94
|
|
|
93
95
|
**Prometheus Metrics** — A dedicated metrics endpoint exports process and system telemetry in Prometheus exposition format, ready for scraping by Prometheus and visualization in Grafana.
|
|
@@ -283,6 +285,14 @@ bm2 start server.ts --name api --wait-ready --listen-timeout 10000
|
|
|
283
285
|
| `--health-check-interval <ms>` | Probe interval | `30000` |
|
|
284
286
|
| `--health-check-timeout <ms>` | Probe timeout | `5000` |
|
|
285
287
|
| `--health-check-max-fails <n>` | Failures before restart | `3` |
|
|
288
|
+
| `--no-daemon`, `-d` | Run in foreground without a daemon (blocks) | `false` |
|
|
289
|
+
|
|
290
|
+
> **Flags are position-independent.** `--no-daemon` (and all other flags) may appear anywhere relative to the script path:
|
|
291
|
+
> ```
|
|
292
|
+
> bm2 start --no-daemon app.ts
|
|
293
|
+
> bm2 start app.ts --no-daemon
|
|
294
|
+
> bm2 start --name api --no-daemon app.ts --watch
|
|
295
|
+
> ```
|
|
286
296
|
|
|
287
297
|
---
|
|
288
298
|
|
|
@@ -415,7 +425,6 @@ bm2 list
|
|
|
415
425
|
|
|
416
426
|
# List processes with live updates
|
|
417
427
|
bm2 list --live
|
|
418
|
-
|
|
419
428
|
```
|
|
420
429
|
|
|
421
430
|
## Notes
|
|
@@ -453,27 +462,24 @@ Cluster mode spawns multiple instances of your application, each running in its
|
|
|
453
462
|
|
|
454
463
|
```bash
|
|
455
464
|
bm2 start server.ts --name api --instances max
|
|
456
|
-
|
|
457
465
|
```
|
|
458
466
|
|
|
459
467
|
```bash
|
|
460
468
|
bm2 start server.ts --name api --instances 4
|
|
461
|
-
|
|
462
469
|
```
|
|
463
470
|
|
|
464
471
|
```bash
|
|
465
472
|
bm2 start server.ts --name api --instances 4 --port 3000
|
|
466
|
-
|
|
467
473
|
```
|
|
468
474
|
|
|
469
475
|
#### ⚠️ Current Status & Limitations
|
|
470
476
|
|
|
471
|
-
While `bm2` provides the orchestration for clustering, please note that **Bun
|
|
477
|
+
While `bm2` provides the orchestration for clustering, please note that **Bun's native cluster implementation is currently limited by the underlying OS:**
|
|
472
478
|
|
|
473
479
|
* **Linux Only:** Port sharing via `reusePort` is only fully supported on **Linux**.
|
|
474
480
|
* **macOS & Windows:** Due to OS-level limitations with `SO_REUSEPORT`, these platforms ignore the `reusePort` option. On these systems, clustering may result in "Address already in use" errors if attempting to bind multiple workers to the same port.
|
|
475
481
|
|
|
476
|
-
`bm2` leverages the native [Bun.serve cluster logic](https://
|
|
482
|
+
`bm2` leverages the native [Bun.serve cluster logic](https://bun.sh/docs/api/http#cluster) to ensure maximum performance, but it remains subject to the runtime's maturity.
|
|
477
483
|
|
|
478
484
|
|
|
479
485
|
#### Environment Variables
|
|
@@ -503,14 +509,13 @@ Bun.serve({
|
|
|
503
509
|
port,
|
|
504
510
|
// Share the same port across multiple processes
|
|
505
511
|
// This is the important part!
|
|
506
|
-
reusePort: true,
|
|
512
|
+
reusePort: true,
|
|
507
513
|
fetch(req) {
|
|
508
514
|
return new Response(`Hello from worker ${workerId} on port ${port}`);
|
|
509
515
|
},
|
|
510
516
|
});
|
|
511
517
|
|
|
512
518
|
console.log(`Worker ${workerId} listening on :${port}`);
|
|
513
|
-
|
|
514
519
|
```
|
|
515
520
|
|
|
516
521
|
---
|
|
@@ -1001,6 +1006,108 @@ bm2 kill
|
|
|
1001
1006
|
|
|
1002
1007
|
---
|
|
1003
1008
|
|
|
1009
|
+
## Foreground Mode (Docker & Containers)
|
|
1010
|
+
|
|
1011
|
+
By default, BM2 spawns a background daemon process and returns immediately — ideal for long-running servers. However, containerized environments like **Docker**, **Kubernetes**, and **Railway** expect the entrypoint process to stay in the **foreground**. If BM2 daemonizes and exits, the container stops.
|
|
1012
|
+
|
|
1013
|
+
Use `--no-daemon` (alias `-d`) to run BM2 in **foreground / blocking mode**. In this mode:
|
|
1014
|
+
|
|
1015
|
+
- No background daemon is spawned.
|
|
1016
|
+
- The `bm2 start` process itself stays alive, blocking the terminal (or container).
|
|
1017
|
+
- All managed child processes are supervised in-process.
|
|
1018
|
+
- Auto-restart and crash recovery still work normally.
|
|
1019
|
+
- The process exits only when all child processes stop or a signal (e.g. `SIGTERM`) is received.
|
|
1020
|
+
|
|
1021
|
+
### Flags
|
|
1022
|
+
|
|
1023
|
+
| Flag | Alias | Description |
|
|
1024
|
+
|---|---|---|
|
|
1025
|
+
| `--no-daemon` | `-d` | Run in foreground without spawning a background daemon |
|
|
1026
|
+
|
|
1027
|
+
### Usage
|
|
1028
|
+
|
|
1029
|
+
```bash
|
|
1030
|
+
# Foreground — blocks until the process exits
|
|
1031
|
+
bm2 start --no-daemon server.ts
|
|
1032
|
+
|
|
1033
|
+
# Flag order is flexible — these are all equivalent
|
|
1034
|
+
bm2 start server.ts --no-daemon
|
|
1035
|
+
bm2 start --no-daemon server.ts --name api
|
|
1036
|
+
bm2 start --name api --no-daemon server.ts
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
### Docker
|
|
1040
|
+
|
|
1041
|
+
This is the recommended pattern for running BM2 inside a Docker container. The `CMD` instruction should use `--no-daemon` so BM2 stays as PID 1 (or the foreground entrypoint) and Docker can track its lifecycle correctly.
|
|
1042
|
+
|
|
1043
|
+
**Dockerfile**
|
|
1044
|
+
|
|
1045
|
+
```dockerfile
|
|
1046
|
+
FROM oven/bun:latest
|
|
1047
|
+
|
|
1048
|
+
WORKDIR /app
|
|
1049
|
+
|
|
1050
|
+
COPY package.json bun.lockb ./
|
|
1051
|
+
RUN bun install --frozen-lockfile
|
|
1052
|
+
|
|
1053
|
+
COPY . .
|
|
1054
|
+
|
|
1055
|
+
# Install BM2 globally
|
|
1056
|
+
RUN bun add -g bm2
|
|
1057
|
+
|
|
1058
|
+
# Use --no-daemon so BM2 stays in the foreground
|
|
1059
|
+
CMD ["bm2", "start", "--no-daemon", "./server.ts"]
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
**With additional options**
|
|
1063
|
+
|
|
1064
|
+
```dockerfile
|
|
1065
|
+
CMD ["bm2", "start", "--no-daemon", "--name", "api", "--instances", "2", "./server.ts"]
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
**With an ecosystem file**
|
|
1069
|
+
|
|
1070
|
+
```dockerfile
|
|
1071
|
+
CMD ["bm2", "start", "--no-daemon", "ecosystem.config.json"]
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
> **Note:** Ecosystem file support with `--no-daemon` behaves identically to normal mode — all `apps` entries are started and supervised in-process.
|
|
1075
|
+
|
|
1076
|
+
### Docker Compose
|
|
1077
|
+
|
|
1078
|
+
```yaml
|
|
1079
|
+
services:
|
|
1080
|
+
api:
|
|
1081
|
+
build: .
|
|
1082
|
+
ports:
|
|
1083
|
+
- "3000:3000"
|
|
1084
|
+
command: ["bm2", "start", "--no-daemon", "./server.ts"]
|
|
1085
|
+
restart: unless-stopped
|
|
1086
|
+
```
|
|
1087
|
+
|
|
1088
|
+
### Kubernetes
|
|
1089
|
+
|
|
1090
|
+
```yaml
|
|
1091
|
+
containers:
|
|
1092
|
+
- name: api
|
|
1093
|
+
image: your-org/api:latest
|
|
1094
|
+
command: ["bm2", "start", "--no-daemon", "./server.ts"]
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
### Behaviour Differences vs. Daemon Mode
|
|
1098
|
+
|
|
1099
|
+
| Behaviour | Daemon mode (default) | Foreground mode (`--no-daemon`) |
|
|
1100
|
+
|---|---|---|
|
|
1101
|
+
| CLI returns immediately | ✅ | ❌ — blocks |
|
|
1102
|
+
| Background daemon spawned | ✅ | ❌ |
|
|
1103
|
+
| Unix socket IPC | ✅ | ❌ |
|
|
1104
|
+
| Auto-restart on crash | ✅ | ✅ |
|
|
1105
|
+
| `bm2 list` / `bm2 logs` from another shell | ✅ | ❌ — no daemon to query |
|
|
1106
|
+
| Suitable for Docker / containers | ❌ | ✅ |
|
|
1107
|
+
| Suitable for long-running servers | ✅ | ✅ |
|
|
1108
|
+
|
|
1109
|
+
---
|
|
1110
|
+
|
|
1004
1111
|
## Configuration Reference
|
|
1005
1112
|
|
|
1006
1113
|
### Ecosystem File Format
|
|
@@ -1042,6 +1149,7 @@ The complete set of options available for each entry in the apps array:
|
|
|
1042
1149
|
| `sourceMapSupport` | `boolean` | `false` | Enable source map support |
|
|
1043
1150
|
| `waitReady` | `boolean` | `false` | Wait for process to emit ready signal |
|
|
1044
1151
|
| `listenTimeout` | `number` | `3000` | Timeout when waiting for ready signal |
|
|
1152
|
+
| `noDaemon` | `boolean` | `false` | Run in foreground without a daemon |
|
|
1045
1153
|
|
|
1046
1154
|
---
|
|
1047
1155
|
|
|
@@ -1273,7 +1381,7 @@ groups:
|
|
|
1273
1381
|
labels:
|
|
1274
1382
|
severity: critical
|
|
1275
1383
|
annotations:
|
|
1276
|
-
summary: "Process {{
|
|
1384
|
+
summary: "Process {{ $labels.name }} is down"
|
|
1277
1385
|
|
|
1278
1386
|
- alert: HighRestartRate
|
|
1279
1387
|
expr: rate(bm2_process_restarts_total[5m]) > 0.1
|
|
@@ -1281,7 +1389,7 @@ groups:
|
|
|
1281
1389
|
labels:
|
|
1282
1390
|
severity: warning
|
|
1283
1391
|
annotations:
|
|
1284
|
-
summary: "Process {{
|
|
1392
|
+
summary: "Process {{ $labels.name }} is restarting frequently"
|
|
1285
1393
|
|
|
1286
1394
|
- alert: HighMemoryUsage
|
|
1287
1395
|
expr: bm2_process_memory_bytes > 1e9
|
|
@@ -1289,7 +1397,7 @@ groups:
|
|
|
1289
1397
|
labels:
|
|
1290
1398
|
severity: warning
|
|
1291
1399
|
annotations:
|
|
1292
|
-
summary: "Process {{
|
|
1400
|
+
summary: "Process {{ $labels.name }} using > 1GB memory"
|
|
1293
1401
|
```
|
|
1294
1402
|
|
|
1295
1403
|
---
|
|
@@ -1885,6 +1993,7 @@ The `ProcessManager` provides the same process management capabilities but runs
|
|
|
1885
1993
|
| Module System | `pm2 install` | `bm2 module install` |
|
|
1886
1994
|
| TypeScript | Requires compilation | Native support |
|
|
1887
1995
|
| File Watching | `chokidar` | Native `fs.watch` |
|
|
1996
|
+
| Docker / Foreground Mode | `--no-daemon` flag | `--no-daemon` / `-d` flag |
|
|
1888
1997
|
|
|
1889
1998
|
---
|
|
1890
1999
|
|
|
@@ -1948,6 +2057,18 @@ bm2 start server.ts --name api --cron "0 3 * * *"
|
|
|
1948
2057
|
}
|
|
1949
2058
|
```
|
|
1950
2059
|
|
|
2060
|
+
### Docker Container (Foreground Mode)
|
|
2061
|
+
|
|
2062
|
+
```dockerfile
|
|
2063
|
+
FROM oven/bun:latest
|
|
2064
|
+
WORKDIR /app
|
|
2065
|
+
COPY package.json bun.lockb ./
|
|
2066
|
+
RUN bun install --frozen-lockfile
|
|
2067
|
+
COPY . .
|
|
2068
|
+
RUN bun add -g bm2
|
|
2069
|
+
CMD ["bm2", "start", "--no-daemon", "./server.ts"]
|
|
2070
|
+
```
|
|
2071
|
+
|
|
1951
2072
|
### Full Production Setup
|
|
1952
2073
|
|
|
1953
2074
|
```
|
|
@@ -2121,6 +2242,18 @@ bm2 ping
|
|
|
2121
2242
|
|
|
2122
2243
|
This returns the daemon PID and uptime. If it doesn't respond, the daemon needs to be restarted.
|
|
2123
2244
|
|
|
2245
|
+
### Container exits immediately
|
|
2246
|
+
|
|
2247
|
+
If your Docker container exits right after starting, you are likely missing `--no-daemon`. Without it, BM2 daemonizes and the foreground process exits, causing Docker to stop the container.
|
|
2248
|
+
|
|
2249
|
+
```dockerfile
|
|
2250
|
+
# ❌ Wrong — BM2 daemonizes and the container exits
|
|
2251
|
+
CMD ["bm2", "start", "./server.ts"]
|
|
2252
|
+
|
|
2253
|
+
# ✅ Correct — BM2 stays in the foreground
|
|
2254
|
+
CMD ["bm2", "start", "--no-daemon", "./server.ts"]
|
|
2255
|
+
```
|
|
2256
|
+
|
|
2124
2257
|
---
|
|
2125
2258
|
|
|
2126
2259
|
## File Structure
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bm2",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.36",
|
|
4
4
|
"description": "A blazing-fast, full-featured process manager built entirely on Bun native APIs. The modern PM2 replacement — zero Node.js dependencies, pure Bun performance.",
|
|
5
5
|
"main": "src/api.ts",
|
|
6
6
|
"module": "src/api.ts",
|
package/src/daemon-v1.ts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BM2 — Bun Process Manager
|
|
3
|
+
* A production-grade process manager for Bun.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Fork & cluster execution modes
|
|
7
|
+
* - Auto-restart & crash recovery
|
|
8
|
+
* - Health checks & monitoring
|
|
9
|
+
* - Log management & rotation
|
|
10
|
+
* - Deployment support
|
|
11
|
+
*
|
|
12
|
+
* https://github.com/your-org/bm2
|
|
13
|
+
* License: GPL-3.0-only
|
|
14
|
+
* Author: Zak <zak@maxxpainn.com>
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { ProcessManager } from "./process-manager";
|
|
18
|
+
import { Dashboard } from "./dashboard";
|
|
19
|
+
import { ModuleManager } from "./module-manager";
|
|
20
|
+
import {
|
|
21
|
+
DAEMON_SOCKET,
|
|
22
|
+
DAEMON_PID_FILE,
|
|
23
|
+
DASHBOARD_PORT,
|
|
24
|
+
METRICS_PORT,
|
|
25
|
+
} from "./constants";
|
|
26
|
+
import { ensureDirs } from "./utils";
|
|
27
|
+
import { unlinkSync, existsSync } from "fs";
|
|
28
|
+
import type { DaemonMessage, DaemonResponse } from "./types";
|
|
29
|
+
import type { BunRequest, Server } from "bun";
|
|
30
|
+
|
|
31
|
+
ensureDirs();
|
|
32
|
+
|
|
33
|
+
let server: Server<any> | null = null
|
|
34
|
+
const pm = new ProcessManager();
|
|
35
|
+
const dashboard = new Dashboard(pm);
|
|
36
|
+
const moduleManager = new ModuleManager(pm);
|
|
37
|
+
|
|
38
|
+
const args = process.argv.slice(2);
|
|
39
|
+
|
|
40
|
+
// Checks if '--debug' exists anywhere in the arguments
|
|
41
|
+
const debugMode = args.includes('--debug');
|
|
42
|
+
|
|
43
|
+
// Clean up existing socket
|
|
44
|
+
if (existsSync(DAEMON_SOCKET)) {
|
|
45
|
+
try { unlinkSync(DAEMON_SOCKET); } catch {}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Write PID file
|
|
49
|
+
await Bun.write(DAEMON_PID_FILE, String(process.pid));
|
|
50
|
+
|
|
51
|
+
// Load modules
|
|
52
|
+
await moduleManager.loadAll();
|
|
53
|
+
|
|
54
|
+
// Start metric collection
|
|
55
|
+
const metricsInterval = setInterval(() => {
|
|
56
|
+
pm.getMetrics();
|
|
57
|
+
}, 2000);
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
const handleServerRequests = async (req: Request) => {
|
|
61
|
+
|
|
62
|
+
if (req.method !== "POST") {
|
|
63
|
+
return Response.json(
|
|
64
|
+
{ type: "error", error: "Method Not Allowed", success: false },
|
|
65
|
+
{ status: 405 }
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
|
|
71
|
+
const msg: DaemonMessage = await req.json() as DaemonMessage;
|
|
72
|
+
|
|
73
|
+
const response = await handleMessage(msg);
|
|
74
|
+
|
|
75
|
+
return Response.json(response);
|
|
76
|
+
|
|
77
|
+
} catch (err: any) {
|
|
78
|
+
return Response.json(
|
|
79
|
+
{ type: "error", error: err.message, success: false },
|
|
80
|
+
{ status: 500 }
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const serverOptions = {
|
|
86
|
+
unix: DAEMON_SOCKET,
|
|
87
|
+
fetch: handleServerRequests
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function handleMessage(msg: DaemonMessage): Promise<DaemonResponse> {
|
|
91
|
+
try {
|
|
92
|
+
switch (msg.type) {
|
|
93
|
+
case "start": {
|
|
94
|
+
const states = await pm.start(msg.data);
|
|
95
|
+
return { type: "start", data: states, success: true, id: msg.id };
|
|
96
|
+
}
|
|
97
|
+
case "stop": {
|
|
98
|
+
const states = await pm.stop(msg.data.target);
|
|
99
|
+
return { type: "stop", data: states, success: true, id: msg.id };
|
|
100
|
+
}
|
|
101
|
+
case "restart": {
|
|
102
|
+
const states = await pm.restart(msg.data.target);
|
|
103
|
+
return { type: "restart", data: states, success: true, id: msg.id };
|
|
104
|
+
}
|
|
105
|
+
case "reload": {
|
|
106
|
+
const states = await pm.reload(msg.data.target);
|
|
107
|
+
return { type: "reload", data: states, success: true, id: msg.id };
|
|
108
|
+
}
|
|
109
|
+
case "delete": {
|
|
110
|
+
const states = await pm.del(msg.data.target);
|
|
111
|
+
return { type: "delete", data: states, success: true, id: msg.id };
|
|
112
|
+
}
|
|
113
|
+
case "scale": {
|
|
114
|
+
const states = await pm.scale(msg.data.target, msg.data.count);
|
|
115
|
+
return { type: "scale", data: states, success: true, id: msg.id };
|
|
116
|
+
}
|
|
117
|
+
case "stopAll": {
|
|
118
|
+
const states = await pm.stopAll();
|
|
119
|
+
return { type: "stopAll", data: states, success: true, id: msg.id };
|
|
120
|
+
}
|
|
121
|
+
case "restartAll": {
|
|
122
|
+
const states = await pm.restartAll();
|
|
123
|
+
return { type: "restartAll", data: states, success: true, id: msg.id };
|
|
124
|
+
}
|
|
125
|
+
case "reloadAll": {
|
|
126
|
+
const states = await pm.reloadAll();
|
|
127
|
+
return { type: "reloadAll", data: states, success: true, id: msg.id };
|
|
128
|
+
}
|
|
129
|
+
case "deleteAll": {
|
|
130
|
+
const states = await pm.deleteAll();
|
|
131
|
+
return { type: "deleteAll", data: states, success: true, id: msg.id };
|
|
132
|
+
}
|
|
133
|
+
case "list": {
|
|
134
|
+
return { type: "list", data: pm.list(), success: true, id: msg.id };
|
|
135
|
+
}
|
|
136
|
+
case "describe": {
|
|
137
|
+
return { type: "describe", data: pm.describe(msg.data.target), success: true, id: msg.id };
|
|
138
|
+
}
|
|
139
|
+
case "logs": {
|
|
140
|
+
const logs = await pm.getLogs(msg.data.target, msg.data.lines);
|
|
141
|
+
return { type: "logs", data: logs, success: true, id: msg.id };
|
|
142
|
+
}
|
|
143
|
+
case "flush": {
|
|
144
|
+
await pm.flushLogs(msg.data?.target);
|
|
145
|
+
return { type: "flush", success: true, id: msg.id };
|
|
146
|
+
}
|
|
147
|
+
case "save": {
|
|
148
|
+
await pm.save();
|
|
149
|
+
return { type: "save", success: true, id: msg.id };
|
|
150
|
+
}
|
|
151
|
+
case "resurrect": {
|
|
152
|
+
const states = await pm.resurrect();
|
|
153
|
+
return { type: "resurrect", data: states, success: true, id: msg.id };
|
|
154
|
+
}
|
|
155
|
+
case "ecosystem": {
|
|
156
|
+
const states = await pm.startEcosystem(msg.data);
|
|
157
|
+
return { type: "ecosystem", data: states, success: true, id: msg.id };
|
|
158
|
+
}
|
|
159
|
+
case "signal": {
|
|
160
|
+
await pm.sendSignal(msg.data.target, msg.data.signal);
|
|
161
|
+
return { type: "signal", success: true, id: msg.id };
|
|
162
|
+
}
|
|
163
|
+
case "reset": {
|
|
164
|
+
const states = await pm.reset(msg.data.target);
|
|
165
|
+
return { type: "reset", data: states, success: true, id: msg.id };
|
|
166
|
+
}
|
|
167
|
+
case "metrics": {
|
|
168
|
+
const metrics = await pm.getMetrics();
|
|
169
|
+
return { type: "metrics", data: metrics, success: true, id: msg.id };
|
|
170
|
+
}
|
|
171
|
+
case "metricsHistory": {
|
|
172
|
+
const history = pm.getMetricsHistory(msg.data?.seconds || 300);
|
|
173
|
+
return { type: "metricsHistory", data: history, success: true, id: msg.id };
|
|
174
|
+
}
|
|
175
|
+
case "prometheus": {
|
|
176
|
+
const prom = pm.getPrometheusMetrics();
|
|
177
|
+
return { type: "prometheus", data: prom, success: true, id: msg.id };
|
|
178
|
+
}
|
|
179
|
+
case "dashboard": {
|
|
180
|
+
const port = msg.data?.port || DASHBOARD_PORT;
|
|
181
|
+
const metricsPort = msg.data?.metricsPort || METRICS_PORT;
|
|
182
|
+
dashboard.start(port, metricsPort);
|
|
183
|
+
return { type: "dashboard", data: { port, metricsPort }, success: true, id: msg.id };
|
|
184
|
+
}
|
|
185
|
+
case "dashboardStop": {
|
|
186
|
+
dashboard.stop();
|
|
187
|
+
return { type: "dashboardStop", success: true, id: msg.id };
|
|
188
|
+
}
|
|
189
|
+
case "moduleInstall": {
|
|
190
|
+
const path = await moduleManager.install(msg.data.module);
|
|
191
|
+
return { type: "moduleInstall", data: { path }, success: true, id: msg.id };
|
|
192
|
+
}
|
|
193
|
+
case "moduleUninstall": {
|
|
194
|
+
await moduleManager.uninstall(msg.data.module);
|
|
195
|
+
return { type: "moduleUninstall", success: true, id: msg.id };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
case "moduleList": {
|
|
199
|
+
return { type: "moduleList", data: moduleManager.list(), success: true, id: msg.id };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
case "daemonReload": {
|
|
203
|
+
if (!server) {
|
|
204
|
+
server = Bun.serve(serverOptions);
|
|
205
|
+
} else {
|
|
206
|
+
server.reload(serverOptions)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return { type: "daemonReload", data: `Daemon reloaded`, success: true, id: msg.id };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
case "ping": {
|
|
213
|
+
return {
|
|
214
|
+
type: "pong",
|
|
215
|
+
data: { pid: process.pid, uptime: process.uptime() },
|
|
216
|
+
success: true,
|
|
217
|
+
id: msg.id,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
case "kill": {
|
|
222
|
+
await pm.stopAll();
|
|
223
|
+
dashboard.stop();
|
|
224
|
+
clearInterval(metricsInterval);
|
|
225
|
+
setTimeout(() => process.exit(0), 200);
|
|
226
|
+
return { type: "kill", success: true, id: msg.id };
|
|
227
|
+
}
|
|
228
|
+
default:
|
|
229
|
+
return { type: "error", error: `Unknown command: ${msg.type}`, success: false, id: msg.id };
|
|
230
|
+
}
|
|
231
|
+
} catch (err: Error | any) {
|
|
232
|
+
let error = err.message;
|
|
233
|
+
if (debugMode) {
|
|
234
|
+
error = `Message: ${err.message}\nStack: ${err.stack}`
|
|
235
|
+
console.error(err, err.stack)
|
|
236
|
+
}
|
|
237
|
+
return { type: "error", error, success: false, id: msg.id };
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
server = Bun.serve(serverOptions);
|
|
243
|
+
|
|
244
|
+
console.log(`Listening on ${server.url}`);
|