@daemonitor/plugins 1.1.14 → 1.1.16

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.
@@ -98,6 +98,27 @@ function availableMem() {
98
98
  // fall through to freemem()
99
99
  }
100
100
  }
101
+ if (platform() === "darwin") {
102
+ // macOS keeps `freemem()` near zero by design (RAM held as cache/compressed).
103
+ // Reclaimable memory ≈ free + inactive + speculative + purgeable pages —
104
+ // this tracks the kernel's own "available" (memory_pressure free %), so a
105
+ // healthy Mac doesn't read as 100% used.
106
+ try {
107
+ const out = execSync("vm_stat", { encoding: "utf8", timeout: 4000 });
108
+ const page = parseInt(out.match(/page size of (\d+) bytes/)?.[1] || "16384", 10);
109
+ const pages = (re) => parseInt(out.match(re)?.[1] || "0", 10);
110
+ const free = pages(/Pages free:\s+(\d+)/);
111
+ const inactive = pages(/Pages inactive:\s+(\d+)/);
112
+ const speculative = pages(/Pages speculative:\s+(\d+)/);
113
+ const purgeable = pages(/Pages purgeable:\s+(\d+)/);
114
+ const avail = (free + inactive + speculative + purgeable) * page;
115
+ if (avail > 0)
116
+ return avail;
117
+ }
118
+ catch {
119
+ // fall through to freemem()
120
+ }
121
+ }
101
122
  return freemem();
102
123
  }
103
124
  // Cumulative rx/tx byte counters summed across real interfaces (Linux
@@ -105,27 +126,55 @@ function availableMem() {
105
126
  // so the figure reflects actual host network traffic, not container-to-host
106
127
  // chatter. Returns null off Linux (rate is then omitted, not faked).
107
128
  function readNetTotals() {
108
- if (platform() !== "linux")
109
- return null;
110
- try {
111
- const data = readFileSync("/proc/net/dev", "utf8");
112
- let rx = 0, tx = 0;
113
- for (const line of data.split("\n")) {
114
- const m = line.match(/^\s*([^:]+):\s*(.*)$/);
115
- if (!m)
116
- continue;
117
- const iface = m[1].trim();
118
- if (iface === "lo" || /^(veth|docker|br-|lxcbr|virbr|tap|tun)/.test(iface))
119
- continue;
120
- const cols = m[2].trim().split(/\s+/).map(Number);
121
- rx += cols[0] || 0; // column 1 = rx bytes
122
- tx += cols[8] || 0; // column 9 = tx bytes
129
+ if (platform() === "linux") {
130
+ try {
131
+ const data = readFileSync("/proc/net/dev", "utf8");
132
+ let rx = 0, tx = 0;
133
+ for (const line of data.split("\n")) {
134
+ const m = line.match(/^\s*([^:]+):\s*(.*)$/);
135
+ if (!m)
136
+ continue;
137
+ const iface = m[1].trim();
138
+ if (iface === "lo" || /^(veth|docker|br-|lxcbr|virbr|tap|tun)/.test(iface))
139
+ continue;
140
+ const cols = m[2].trim().split(/\s+/).map(Number);
141
+ rx += cols[0] || 0; // column 1 = rx bytes
142
+ tx += cols[8] || 0; // column 9 = tx bytes
143
+ }
144
+ return { rx, tx };
145
+ }
146
+ catch {
147
+ return null;
123
148
  }
124
- return { rx, tx };
125
149
  }
126
- catch {
127
- return null;
150
+ if (platform() === "darwin") {
151
+ // `netstat -ibn`: Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll.
152
+ // Per-interface byte counters repeat across a NIC's address rows, so take one
153
+ // row per interface; skip loopback and virtual (bridge/utun/awdl/llw/gif/stf/ap).
154
+ try {
155
+ const out = execSync("netstat -ibn", { encoding: "utf8", timeout: 4000 });
156
+ let rx = 0, tx = 0;
157
+ const seen = new Set();
158
+ for (const line of out.split("\n").slice(1)) {
159
+ const c = line.trim().split(/\s+/);
160
+ if (c.length < 10)
161
+ continue;
162
+ const name = c[0];
163
+ if (!name || name === "lo0" || /^(bridge|utun|llw|awdl|gif|stf|ap\d|anpi|en\d*_)/.test(name))
164
+ continue;
165
+ if (seen.has(name))
166
+ continue;
167
+ seen.add(name);
168
+ rx += Number(c[6]) || 0; // Ibytes
169
+ tx += Number(c[9]) || 0; // Obytes
170
+ }
171
+ return { rx, tx };
172
+ }
173
+ catch {
174
+ return null;
175
+ }
128
176
  }
177
+ return null;
129
178
  }
130
179
  // Host OS metrics: cpu (from cpus().times), memory, disk, load, uptime,
131
180
  // addresses, and network throughput. Matches the frontend `os` fleetAdapter case.
@@ -245,6 +245,7 @@ async function collectDevice(t) {
245
245
  portsUp,
246
246
  portsTotal,
247
247
  cpuPct,
248
+ cpuCores: procLoads.length || undefined, // for load-per-core normalization
248
249
  load1: load1n,
249
250
  loadavg: loadavg.length ? loadavg : undefined,
250
251
  memPct,
@@ -89,6 +89,25 @@ export function createWebsitePlugin() {
89
89
  const start = Date.now();
90
90
  const label = ep.name || ep.url;
91
91
  const uid = `web-${(ep.name || ep.url).replace(/[^a-zA-Z0-9_.-]+/g, "-")}`;
92
+ // Origin-only monitor: skip the public tier (unreachable behind a CDN bot
93
+ // challenge) and report the direct origin check as the endpoint's health.
94
+ if (ep.originOnly && ep.origin?.url) {
95
+ const o = await checkOrigin(ep);
96
+ await plugin.send({
97
+ name: label,
98
+ url: ep.url || o.url,
99
+ status: o.status,
100
+ duration: o.duration,
101
+ ok: o.ok,
102
+ originOnly: true,
103
+ hasAllExpectedStrings: o.hasAllExpectedStrings,
104
+ hasAnyUnexpectedStrings: o.hasAnyUnexpectedStrings,
105
+ missingExpected: o.missingExpected,
106
+ matchedUnexpected: o.matchedUnexpected,
107
+ error: o.error,
108
+ }, uid);
109
+ return;
110
+ }
92
111
  let publicResult;
93
112
  try {
94
113
  const ctrl = new AbortController();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daemonitor/plugins",
3
- "version": "1.1.14",
3
+ "version": "1.1.16",
4
4
  "description": "daemonitor plugins",
5
5
  "types": "types/index.d.ts",
6
6
  "main": "dist/index.js",