badmfck-api-server 4.1.25 → 4.1.27

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.
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ProcessMonitor = void 0;
7
+ const os_1 = __importDefault(require("os"));
8
+ const v8_1 = __importDefault(require("v8"));
9
+ const perf_hooks_1 = require("perf_hooks");
10
+ const promises_1 = __importDefault(require("fs/promises"));
11
+ class ProcessMonitor {
12
+ static _inited = false;
13
+ static _eld = null;
14
+ static _gcObserver = null;
15
+ static _gc = {
16
+ totalCount: 0,
17
+ totalTimeMs: 0,
18
+ maxPauseMs: 0,
19
+ byKind: {},
20
+ lastPauses: [],
21
+ };
22
+ static _prevCpu = process.cpuUsage();
23
+ static _prevCpuAt = Date.now();
24
+ static _cpuPct = { userPct: 0, systemPct: 0 };
25
+ static _eluPrev = perf_hooks_1.performance.eventLoopUtilization();
26
+ static _elu = { idle: 0, active: 0, utilizationPct: 0 };
27
+ static _processStartedAt = Date.now() - process.uptime() * 1000;
28
+ static init() {
29
+ if (this._inited)
30
+ return;
31
+ this._inited = true;
32
+ this._eld = (0, perf_hooks_1.monitorEventLoopDelay)({ resolution: 20 });
33
+ this._eld.enable();
34
+ this._gcObserver = new perf_hooks_1.PerformanceObserver((list) => {
35
+ for (const entry of list.getEntries()) {
36
+ const kind = this._mapGcKind(entry.detail?.kind ?? entry.kind);
37
+ this._gc.totalCount++;
38
+ this._gc.totalTimeMs += entry.duration;
39
+ if (entry.duration > this._gc.maxPauseMs)
40
+ this._gc.maxPauseMs = entry.duration;
41
+ const bucket = this._gc.byKind[kind] ?? { count: 0, timeMs: 0 };
42
+ bucket.count++;
43
+ bucket.timeMs += entry.duration;
44
+ this._gc.byKind[kind] = bucket;
45
+ this._gc.lastPauses.push({ kind, ms: entry.duration, timestamp: Date.now() });
46
+ if (this._gc.lastPauses.length > 20)
47
+ this._gc.lastPauses.shift();
48
+ }
49
+ });
50
+ try {
51
+ this._gcObserver.observe({ entryTypes: ["gc"], buffered: false });
52
+ }
53
+ catch {
54
+ try {
55
+ this._gcObserver.observe({ type: "gc" });
56
+ }
57
+ catch { }
58
+ }
59
+ const cpuTimer = setInterval(() => this._sampleCpu(), 5000);
60
+ if (cpuTimer.unref)
61
+ cpuTimer.unref();
62
+ const eluTimer = setInterval(() => this._sampleELU(), 5000);
63
+ if (eluTimer.unref)
64
+ eluTimer.unref();
65
+ }
66
+ static _sampleCpu() {
67
+ const now = process.cpuUsage();
68
+ const nowAt = Date.now();
69
+ const dtMs = nowAt - this._prevCpuAt;
70
+ if (dtMs <= 0)
71
+ return;
72
+ const userPct = (now.user - this._prevCpu.user) / (dtMs * 1000) * 100;
73
+ const systemPct = (now.system - this._prevCpu.system) / (dtMs * 1000) * 100;
74
+ this._cpuPct = {
75
+ userPct: Math.round(userPct * 10) / 10,
76
+ systemPct: Math.round(systemPct * 10) / 10,
77
+ };
78
+ this._prevCpu = now;
79
+ this._prevCpuAt = nowAt;
80
+ }
81
+ static _sampleELU() {
82
+ const cur = perf_hooks_1.performance.eventLoopUtilization();
83
+ const delta = perf_hooks_1.performance.eventLoopUtilization(cur, this._eluPrev);
84
+ this._elu = {
85
+ idle: delta.idle,
86
+ active: delta.active,
87
+ utilizationPct: Math.round(delta.utilization * 10000) / 100,
88
+ };
89
+ this._eluPrev = cur;
90
+ }
91
+ static _mapGcKind(kind) {
92
+ if (typeof kind === "string")
93
+ return kind;
94
+ switch (kind) {
95
+ case 1: return "minor";
96
+ case 2: return "major";
97
+ case 4: return "incremental";
98
+ case 8: return "weakcb";
99
+ case 15: return "all";
100
+ default: return "unknown";
101
+ }
102
+ }
103
+ static async getSnapshot() {
104
+ const tStart = process.hrtime.bigint();
105
+ await new Promise(r => setImmediate(() => r()));
106
+ const spotLagMs = Number(process.hrtime.bigint() - tStart) / 1e6;
107
+ const mem = process.memoryUsage();
108
+ const heap = v8_1.default.getHeapStatistics();
109
+ const heapSpaces = v8_1.default.getHeapSpaceStatistics().map(s => ({
110
+ name: s.space_name,
111
+ size: s.space_size,
112
+ used: s.space_used_size,
113
+ available: s.space_available_size,
114
+ physical: s.physical_space_size,
115
+ }));
116
+ const procStatus = await this._readProcStatus();
117
+ const io = await this._readProcIo();
118
+ const limitsParsed = await this._readProcLimits();
119
+ const cpuTotal = process.cpuUsage();
120
+ let resource = null;
121
+ try {
122
+ const r = process.resourceUsage();
123
+ resource = {
124
+ maxRSS: r.maxRSS,
125
+ voluntaryContextSwitches: r.voluntaryContextSwitches,
126
+ involuntaryContextSwitches: r.involuntaryContextSwitches,
127
+ fsRead: r.fsRead,
128
+ fsWrite: r.fsWrite,
129
+ signalsCount: r.signalsCount,
130
+ ipcSent: r.ipcSent,
131
+ ipcReceived: r.ipcReceived,
132
+ userCPUTimeMs: Math.round(r.userCPUTime / 1000),
133
+ systemCPUTimeMs: Math.round(r.systemCPUTime / 1000),
134
+ };
135
+ }
136
+ catch { }
137
+ const fdOpen = await this._countFds();
138
+ const fdSoft = limitsParsed?.["Max open files"]?.soft;
139
+ const fdHard = limitsParsed?.["Max open files"]?.hard;
140
+ const h = this._eld;
141
+ const eventLoop = h ? {
142
+ minMs: this._toMsFinite(h.min),
143
+ maxMs: this._toMsFinite(h.max),
144
+ meanMs: this._toMsFinite(h.mean),
145
+ stddevMs: this._toMsFinite(h.stddev),
146
+ p50Ms: this._safePercentileMs(h, 50),
147
+ p90Ms: this._safePercentileMs(h, 90),
148
+ p99Ms: this._safePercentileMs(h, 99),
149
+ utilizationPct: this._elu.utilizationPct,
150
+ activeHandles: this._safeCount(() => process._getActiveHandles?.()?.length),
151
+ activeRequests: this._safeCount(() => process._getActiveRequests?.()?.length),
152
+ spotLagMs: Math.round(spotLagMs * 100) / 100,
153
+ } : null;
154
+ return {
155
+ identity: {
156
+ pid: process.pid,
157
+ ppid: process.ppid,
158
+ title: process.title,
159
+ argv: process.argv,
160
+ execPath: process.execPath,
161
+ cwd: process.cwd(),
162
+ nodeVersion: process.version,
163
+ v8Version: process.versions.v8,
164
+ platform: process.platform,
165
+ arch: process.arch,
166
+ hostname: os_1.default.hostname(),
167
+ user: typeof process.getuid === "function"
168
+ ? { uid: process.getuid(), gid: process.getgid?.() ?? -1 }
169
+ : null,
170
+ startedAtUnix: this._processStartedAt,
171
+ uptimeSec: Math.round(process.uptime()),
172
+ availableParallelism: typeof os_1.default.availableParallelism === "function"
173
+ ? os_1.default.availableParallelism()
174
+ : os_1.default.cpus().length,
175
+ },
176
+ memory: {
177
+ rss: mem.rss,
178
+ heapTotal: mem.heapTotal,
179
+ heapUsed: mem.heapUsed,
180
+ external: mem.external,
181
+ arrayBuffers: mem.arrayBuffers ?? 0,
182
+ heap: {
183
+ sizeLimit: heap.heap_size_limit,
184
+ usedHeap: heap.used_heap_size,
185
+ totalAvailable: heap.total_available_size,
186
+ totalPhysical: heap.total_physical_size,
187
+ mallocedMemory: heap.malloced_memory,
188
+ peakMallocedMemory: heap.peak_malloced_memory,
189
+ numberOfNativeContexts: heap.number_of_native_contexts,
190
+ numberOfDetachedContexts: heap.number_of_detached_contexts,
191
+ },
192
+ heapSpaces,
193
+ procStatus,
194
+ },
195
+ cpu: {
196
+ userPct: this._cpuPct.userPct,
197
+ systemPct: this._cpuPct.systemPct,
198
+ userMicros: cpuTotal.user,
199
+ systemMicros: cpuTotal.system,
200
+ resource,
201
+ },
202
+ eventLoop,
203
+ gc: {
204
+ totalCount: this._gc.totalCount,
205
+ totalTimeMs: Math.round(this._gc.totalTimeMs * 100) / 100,
206
+ maxPauseMs: Math.round(this._gc.maxPauseMs * 100) / 100,
207
+ byKind: this._gc.byKind,
208
+ lastPauses: this._gc.lastPauses.slice(-20),
209
+ },
210
+ fileDescriptors: {
211
+ open: fdOpen,
212
+ limitSoft: fdSoft ? this._parseLimitValue(fdSoft) : null,
213
+ limitHard: fdHard ? this._parseLimitValue(fdHard) : null,
214
+ },
215
+ io,
216
+ limits: limitsParsed,
217
+ };
218
+ }
219
+ static async _readProcStatus() {
220
+ try {
221
+ const txt = await promises_1.default.readFile(`/proc/${process.pid}/status`, "utf-8");
222
+ const keys = ["VmPeak", "VmSize", "VmHWM", "VmRSS", "VmData", "VmStk", "VmExe", "VmSwap", "Threads"];
223
+ const result = {};
224
+ for (const line of txt.split("\n")) {
225
+ for (const k of keys) {
226
+ if (line.startsWith(k + ":")) {
227
+ const m = line.match(new RegExp(`${k}:\\s+(\\d+)`));
228
+ if (m) {
229
+ const v = parseInt(m[1], 10);
230
+ result[k] = k === "Threads" ? v : v * 1024;
231
+ }
232
+ }
233
+ }
234
+ }
235
+ return result;
236
+ }
237
+ catch {
238
+ return null;
239
+ }
240
+ }
241
+ static async _readProcIo() {
242
+ try {
243
+ const txt = await promises_1.default.readFile(`/proc/${process.pid}/io`, "utf-8");
244
+ const result = {};
245
+ for (const line of txt.split("\n")) {
246
+ const m = line.match(/^(\w+):\s+(\d+)$/);
247
+ if (m)
248
+ result[m[1]] = parseInt(m[2], 10);
249
+ }
250
+ return result;
251
+ }
252
+ catch {
253
+ return null;
254
+ }
255
+ }
256
+ static async _readProcLimits() {
257
+ try {
258
+ const txt = await promises_1.default.readFile(`/proc/${process.pid}/limits`, "utf-8");
259
+ const result = {};
260
+ const lines = txt.split("\n").slice(1);
261
+ for (const line of lines) {
262
+ const m = line.match(/^(.+?)\s{2,}(\S+)\s+(\S+)\s+(\S+)\s*$/);
263
+ if (m)
264
+ result[m[1].trim()] = { soft: m[2], hard: m[3], unit: m[4] };
265
+ }
266
+ return result;
267
+ }
268
+ catch {
269
+ return null;
270
+ }
271
+ }
272
+ static async _countFds() {
273
+ try {
274
+ const entries = await promises_1.default.readdir(`/proc/${process.pid}/fd`);
275
+ return entries.length;
276
+ }
277
+ catch {
278
+ return null;
279
+ }
280
+ }
281
+ static _parseLimitValue(v) {
282
+ if (v === "unlimited")
283
+ return -1;
284
+ const n = parseInt(v, 10);
285
+ return Number.isFinite(n) ? n : null;
286
+ }
287
+ static _toMsFinite(ns) {
288
+ return Number.isFinite(ns) ? Math.round((ns / 1e6) * 100) / 100 : 0;
289
+ }
290
+ static _safePercentileMs(h, p) {
291
+ try {
292
+ return this._toMsFinite(h.percentile(p));
293
+ }
294
+ catch {
295
+ return 0;
296
+ }
297
+ }
298
+ static _safeCount(fn) {
299
+ try {
300
+ return fn() ?? 0;
301
+ }
302
+ catch {
303
+ return 0;
304
+ }
305
+ }
306
+ }
307
+ exports.ProcessMonitor = ProcessMonitor;
308
+ ProcessMonitor.init();
@@ -0,0 +1,71 @@
1
+ /// <reference types="node" />
2
+ export declare function collectSystemInfo(): Promise<{
3
+ cpu: {
4
+ usage: {
5
+ userPct: number;
6
+ systemPct: number;
7
+ idlePct: number;
8
+ iowaitPct: number;
9
+ } | null;
10
+ count: number;
11
+ models: Record<string, number>;
12
+ loadAvg: number[];
13
+ platform: NodeJS.Platform;
14
+ arch: NodeJS.Architecture;
15
+ uptimeSec: number;
16
+ };
17
+ memory: {
18
+ total: number;
19
+ free: number;
20
+ used: number;
21
+ usedPct: number;
22
+ };
23
+ disk: {
24
+ filesystem: string;
25
+ size: number;
26
+ used: number;
27
+ available: number;
28
+ usePct: string;
29
+ mount: string;
30
+ }[] | null;
31
+ connections: {
32
+ ports: number[];
33
+ total: number;
34
+ topRemote: {
35
+ ip: string;
36
+ count: number;
37
+ }[];
38
+ } | null;
39
+ nginx: {
40
+ installed: boolean;
41
+ version?: undefined;
42
+ status?: undefined;
43
+ listening?: undefined;
44
+ workerCount?: undefined;
45
+ } | {
46
+ installed: boolean;
47
+ version: string;
48
+ status: string;
49
+ listening: string[];
50
+ workerCount: number;
51
+ } | {
52
+ installed: boolean;
53
+ error: string;
54
+ };
55
+ pm2: {
56
+ installed: boolean;
57
+ error?: undefined;
58
+ processes?: undefined;
59
+ } | {
60
+ installed: boolean;
61
+ error: string;
62
+ processes?: undefined;
63
+ } | {
64
+ installed: boolean;
65
+ processes: any;
66
+ error?: undefined;
67
+ } | {
68
+ installed: boolean;
69
+ error: string;
70
+ };
71
+ }>;
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.collectSystemInfo = void 0;
7
+ const os_1 = __importDefault(require("os"));
8
+ const child_process_1 = require("child_process");
9
+ const util_1 = require("util");
10
+ const promises_1 = __importDefault(require("fs/promises"));
11
+ const execP = (0, util_1.promisify)(child_process_1.exec);
12
+ async function safeExec(cmd, timeoutMs = 3000) {
13
+ try {
14
+ const { stdout, stderr } = await execP(cmd, {
15
+ timeout: timeoutMs,
16
+ maxBuffer: 4 * 1024 * 1024,
17
+ shell: "/bin/sh",
18
+ });
19
+ return { ok: true, stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), code: 0 };
20
+ }
21
+ catch (e) {
22
+ return {
23
+ ok: false,
24
+ stdout: e?.stdout != null ? String(e.stdout) : "",
25
+ stderr: e?.stderr != null ? String(e.stderr) : String(e?.message ?? e),
26
+ code: typeof e?.code === "number" ? e.code : -1,
27
+ };
28
+ }
29
+ }
30
+ async function commandExists(cmd) {
31
+ const r = await safeExec(`command -v ${cmd}`, 1000);
32
+ return r.ok && r.stdout.trim().length > 0;
33
+ }
34
+ function cpuStatic() {
35
+ const cpus = os_1.default.cpus();
36
+ const models = {};
37
+ for (const c of cpus)
38
+ models[c.model] = (models[c.model] ?? 0) + 1;
39
+ return {
40
+ count: cpus.length,
41
+ models,
42
+ loadAvg: os_1.default.loadavg(),
43
+ platform: process.platform,
44
+ arch: process.arch,
45
+ uptimeSec: os_1.default.uptime(),
46
+ };
47
+ }
48
+ async function cpuUsage(sampleMs = 200) {
49
+ if (process.platform !== "linux")
50
+ return null;
51
+ const read = async () => {
52
+ try {
53
+ const txt = await promises_1.default.readFile("/proc/stat", "utf-8");
54
+ const line = txt.split("\n", 1)[0];
55
+ const parts = line.split(/\s+/).slice(1).map(s => parseInt(s, 10) || 0);
56
+ return {
57
+ user: parts[0] ?? 0,
58
+ nice: parts[1] ?? 0,
59
+ system: parts[2] ?? 0,
60
+ idle: parts[3] ?? 0,
61
+ iowait: parts[4] ?? 0,
62
+ irq: parts[5] ?? 0,
63
+ softirq: parts[6] ?? 0,
64
+ steal: parts[7] ?? 0,
65
+ };
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ };
71
+ const a = await read();
72
+ if (!a)
73
+ return null;
74
+ await new Promise(r => setTimeout(r, sampleMs));
75
+ const b = await read();
76
+ if (!b)
77
+ return null;
78
+ const sum = (x) => x.user + x.nice + x.system + x.idle + x.iowait + x.irq + x.softirq + x.steal;
79
+ const total = sum(b) - sum(a);
80
+ if (total <= 0)
81
+ return null;
82
+ const pct = (delta) => Math.round((delta / total) * 1000) / 10;
83
+ return {
84
+ userPct: pct(b.user + b.nice - a.user - a.nice),
85
+ systemPct: pct(b.system - a.system),
86
+ idlePct: pct(b.idle - a.idle),
87
+ iowaitPct: pct(b.iowait - a.iowait),
88
+ };
89
+ }
90
+ function memory() {
91
+ const total = os_1.default.totalmem();
92
+ const free = os_1.default.freemem();
93
+ return {
94
+ total,
95
+ free,
96
+ used: total - free,
97
+ usedPct: Math.round(((total - free) / total) * 1000) / 10,
98
+ };
99
+ }
100
+ async function disk() {
101
+ const r = await safeExec("df -kP");
102
+ if (!r.ok)
103
+ return null;
104
+ const lines = r.stdout.split("\n").slice(1).filter(l => l.trim().length > 0);
105
+ return lines
106
+ .map(line => {
107
+ const parts = line.trim().split(/\s+/);
108
+ if (parts.length < 6)
109
+ return null;
110
+ const sizeKB = parseInt(parts[1], 10) || 0;
111
+ const usedKB = parseInt(parts[2], 10) || 0;
112
+ const availKB = parseInt(parts[3], 10) || 0;
113
+ return {
114
+ filesystem: parts[0],
115
+ size: sizeKB * 1024,
116
+ used: usedKB * 1024,
117
+ available: availKB * 1024,
118
+ usePct: parts[4],
119
+ mount: parts.slice(5).join(" "),
120
+ };
121
+ })
122
+ .filter((d) => d !== null)
123
+ .filter(d => !/^(tmpfs|devtmpfs|squashfs|overlay|udev|none|run)/.test(d.filesystem));
124
+ }
125
+ async function httpConnections(ports = [80, 443]) {
126
+ const portList = ports.join("|");
127
+ const ssCmd = `ss -tnH 2>/dev/null | awk '$1=="ESTAB" && $4 ~ /:(${portList})$/ {print $4, $5}'`;
128
+ let r = await safeExec(ssCmd);
129
+ if (!r.ok || r.stdout.trim().length === 0) {
130
+ const nsCmd = `netstat -tn 2>/dev/null | awk '$6=="ESTABLISHED" && $4 ~ /:(${portList})$/ {print $4, $5}'`;
131
+ r = await safeExec(nsCmd);
132
+ if (!r.ok)
133
+ return null;
134
+ }
135
+ const lines = r.stdout.split("\n").filter(l => l.trim().length > 0);
136
+ const byRemote = {};
137
+ for (const line of lines) {
138
+ const parts = line.split(/\s+/);
139
+ const remote = parts[1] ?? "";
140
+ const ipMatch = remote.match(/^\[?([^\]]+)\]?:\d+$/);
141
+ const ip = ipMatch ? ipMatch[1] : remote;
142
+ byRemote[ip] = (byRemote[ip] ?? 0) + 1;
143
+ }
144
+ const topRemote = Object.entries(byRemote)
145
+ .sort(([, a], [, b]) => b - a)
146
+ .slice(0, 20)
147
+ .map(([ip, count]) => ({ ip, count }));
148
+ return { ports, total: lines.length, topRemote };
149
+ }
150
+ async function nginx() {
151
+ const installed = await commandExists("nginx");
152
+ if (!installed)
153
+ return { installed: false };
154
+ const [version, status, listening, workers] = await Promise.all([
155
+ safeExec("nginx -v 2>&1", 1000),
156
+ safeExec("systemctl is-active nginx 2>/dev/null", 1000),
157
+ safeExec("ss -tlnH 2>/dev/null | awk '{print $4}'", 1000),
158
+ safeExec("pgrep -c nginx 2>/dev/null", 1000),
159
+ ]);
160
+ return {
161
+ installed: true,
162
+ version: (version.stdout || version.stderr).trim(),
163
+ status: status.stdout.trim() || "unknown",
164
+ listening: listening.stdout.split("\n").filter(l => l.trim().length > 0),
165
+ workerCount: parseInt(workers.stdout.trim(), 10) || 0,
166
+ };
167
+ }
168
+ async function pm2() {
169
+ const installed = await commandExists("pm2");
170
+ if (!installed)
171
+ return { installed: false };
172
+ const r = await safeExec("pm2 jlist 2>/dev/null", 3000);
173
+ if (!r.ok)
174
+ return { installed: true, error: r.stderr.slice(0, 500) };
175
+ const text = r.stdout;
176
+ const start = text.indexOf("[");
177
+ const end = text.lastIndexOf("]");
178
+ if (start === -1 || end === -1)
179
+ return { installed: true, error: "no JSON in pm2 jlist output" };
180
+ try {
181
+ const arr = JSON.parse(text.slice(start, end + 1));
182
+ const processes = arr.map((p) => ({
183
+ name: p.name,
184
+ pid: p.pid,
185
+ pm_id: p.pm_id,
186
+ status: p.pm2_env?.status,
187
+ uptime: p.pm2_env?.pm_uptime,
188
+ restarts: p.pm2_env?.restart_time,
189
+ cpu: p.monit?.cpu,
190
+ memory: p.monit?.memory,
191
+ exec_mode: p.pm2_env?.exec_mode,
192
+ instances: p.pm2_env?.instances,
193
+ node_version: p.pm2_env?.node_version,
194
+ }));
195
+ return { installed: true, processes };
196
+ }
197
+ catch {
198
+ return { installed: true, error: "Failed to parse pm2 jlist output" };
199
+ }
200
+ }
201
+ async function collectSystemInfo() {
202
+ const [cpuUsageData, diskData, connectionsData, nginxData, pm2Data] = await Promise.all([
203
+ cpuUsage().catch(() => null),
204
+ disk().catch(() => null),
205
+ httpConnections().catch(() => null),
206
+ nginx().catch(() => ({ installed: false, error: "probe failed" })),
207
+ pm2().catch(() => ({ installed: false, error: "probe failed" })),
208
+ ]);
209
+ return {
210
+ cpu: { ...cpuStatic(), usage: cpuUsageData },
211
+ memory: memory(),
212
+ disk: diskData,
213
+ connections: connectionsData,
214
+ nginx: nginxData,
215
+ pm2: pm2Data,
216
+ };
217
+ }
218
+ exports.collectSystemInfo = collectSystemInfo;