@ceon-oy/monitor-sdk 1.4.0 → 1.5.0

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/dist/index.d.mts CHANGED
@@ -306,6 +306,12 @@ declare class MonitorClient {
306
306
  * Fetch with timeout to prevent hanging requests
307
307
  */
308
308
  private fetchWithTimeout;
309
+ /**
310
+ * Perform an HTTPS request with TLS certificate verification disabled.
311
+ * Used for health checks on servers with self-signed certificates.
312
+ * Uses Node.js built-in `https` module — works reliably in bundled environments.
313
+ */
314
+ private fetchInsecureHttps;
309
315
  private sendSingle;
310
316
  private sendBatch;
311
317
  private startFlushTimer;
@@ -499,15 +505,22 @@ declare class MonitorClient {
499
505
  * Collect system metrics (CPU, RAM, disk) using built-in Node.js modules
500
506
  * and submit to the monitoring server.
501
507
  *
502
- * Uses: os.cpus(), os.totalmem(), os.freemem(), os.hostname(), fs.statfs()
508
+ * Uses: os.cpus(), os.totalmem(), /proc/meminfo (or os.freemem()), os.hostname(), fs.statfs()
503
509
  * Zero dependencies — all built-in Node.js 18.15+
504
510
  */
505
511
  private collectAndSubmitMetrics;
506
512
  /**
507
- * Measure CPU utilization by sampling cpus() twice with a 500ms gap.
508
- * Returns a percentage (0–100).
513
+ * Measure CPU utilization by sampling cpus() twice with a 3s gap.
514
+ * The cumulative counters make this the average utilization over the
515
+ * window, across all cores of the host. Returns a percentage (0–100).
509
516
  */
510
517
  private measureCpuPercent;
518
+ /**
519
+ * Get reclaimable memory in bytes. On Linux, reads MemAvailable from
520
+ * /proc/meminfo so buffers/cache are not counted as used; falls back to
521
+ * os.freemem() (MemFree) on other platforms or if parsing fails.
522
+ */
523
+ private getAvailableMemoryBytes;
511
524
  /**
512
525
  * Collect disk usage for each configured path using fs.statfs() (Node 18.15+).
513
526
  */
package/dist/index.d.ts CHANGED
@@ -306,6 +306,12 @@ declare class MonitorClient {
306
306
  * Fetch with timeout to prevent hanging requests
307
307
  */
308
308
  private fetchWithTimeout;
309
+ /**
310
+ * Perform an HTTPS request with TLS certificate verification disabled.
311
+ * Used for health checks on servers with self-signed certificates.
312
+ * Uses Node.js built-in `https` module — works reliably in bundled environments.
313
+ */
314
+ private fetchInsecureHttps;
309
315
  private sendSingle;
310
316
  private sendBatch;
311
317
  private startFlushTimer;
@@ -499,15 +505,22 @@ declare class MonitorClient {
499
505
  * Collect system metrics (CPU, RAM, disk) using built-in Node.js modules
500
506
  * and submit to the monitoring server.
501
507
  *
502
- * Uses: os.cpus(), os.totalmem(), os.freemem(), os.hostname(), fs.statfs()
508
+ * Uses: os.cpus(), os.totalmem(), /proc/meminfo (or os.freemem()), os.hostname(), fs.statfs()
503
509
  * Zero dependencies — all built-in Node.js 18.15+
504
510
  */
505
511
  private collectAndSubmitMetrics;
506
512
  /**
507
- * Measure CPU utilization by sampling cpus() twice with a 500ms gap.
508
- * Returns a percentage (0–100).
513
+ * Measure CPU utilization by sampling cpus() twice with a 3s gap.
514
+ * The cumulative counters make this the average utilization over the
515
+ * window, across all cores of the host. Returns a percentage (0–100).
509
516
  */
510
517
  private measureCpuPercent;
518
+ /**
519
+ * Get reclaimable memory in bytes. On Linux, reads MemAvailable from
520
+ * /proc/meminfo so buffers/cache are not counted as used; falls back to
521
+ * os.freemem() (MemFree) on other platforms or if parsing fails.
522
+ */
523
+ private getAvailableMemoryBytes;
511
524
  /**
512
525
  * Collect disk usage for each configured path using fs.statfs() (Node 18.15+).
513
526
  */
package/dist/index.js CHANGED
@@ -544,6 +544,45 @@ var MonitorClient = class {
544
544
  clearTimeout(timeoutId);
545
545
  }
546
546
  }
547
+ /**
548
+ * Perform an HTTPS request with TLS certificate verification disabled.
549
+ * Used for health checks on servers with self-signed certificates.
550
+ * Uses Node.js built-in `https` module — works reliably in bundled environments.
551
+ */
552
+ async fetchInsecureHttps(url, options, timeoutMs) {
553
+ const https = await import("https");
554
+ const parsed = new URL(url);
555
+ return new Promise((resolve, reject) => {
556
+ let req;
557
+ const timeoutId = setTimeout(() => {
558
+ req?.destroy();
559
+ reject(new Error(`Request timeout after ${timeoutMs}ms`));
560
+ }, timeoutMs);
561
+ req = https.request(
562
+ {
563
+ hostname: parsed.hostname,
564
+ port: parsed.port || 443,
565
+ path: parsed.pathname + parsed.search,
566
+ method: options.method || "GET",
567
+ headers: options.headers,
568
+ rejectUnauthorized: false
569
+ },
570
+ (res) => {
571
+ clearTimeout(timeoutId);
572
+ res.resume();
573
+ resolve({ status: res.statusCode || 0 });
574
+ }
575
+ );
576
+ req.on("error", (err) => {
577
+ clearTimeout(timeoutId);
578
+ reject(err);
579
+ });
580
+ if (options.body) {
581
+ req.write(options.body);
582
+ }
583
+ req.end();
584
+ });
585
+ }
547
586
  async sendSingle(error) {
548
587
  const response = await this.fetchWithTimeout(`${this.endpoint}/api/v1/errors`, {
549
588
  method: "POST",
@@ -1348,24 +1387,7 @@ var MonitorClient = class {
1348
1387
  "Content-Type": "application/json"
1349
1388
  };
1350
1389
  }
1351
- if (endpoint.allowInsecureTls) {
1352
- try {
1353
- const undici = await import(
1354
- /* webpackIgnore: true */
1355
- "undici"
1356
- );
1357
- const Agent = undici.Agent;
1358
- requestOptions.dispatcher = new Agent({
1359
- connect: { rejectUnauthorized: false }
1360
- });
1361
- } catch {
1362
- }
1363
- }
1364
- const response = await this.fetchWithTimeout(
1365
- endpoint.url,
1366
- requestOptions,
1367
- endpoint.timeoutMs
1368
- );
1390
+ const response = endpoint.allowInsecureTls && endpoint.url.startsWith("https") ? await this.fetchInsecureHttps(endpoint.url, requestOptions, endpoint.timeoutMs) : await this.fetchWithTimeout(endpoint.url, requestOptions, endpoint.timeoutMs);
1369
1391
  const responseTimeMs = Date.now() - startTime;
1370
1392
  const statusCode = response.status;
1371
1393
  let status;
@@ -1546,7 +1568,7 @@ var MonitorClient = class {
1546
1568
  * Collect system metrics (CPU, RAM, disk) using built-in Node.js modules
1547
1569
  * and submit to the monitoring server.
1548
1570
  *
1549
- * Uses: os.cpus(), os.totalmem(), os.freemem(), os.hostname(), fs.statfs()
1571
+ * Uses: os.cpus(), os.totalmem(), /proc/meminfo (or os.freemem()), os.hostname(), fs.statfs()
1550
1572
  * Zero dependencies — all built-in Node.js 18.15+
1551
1573
  */
1552
1574
  async collectAndSubmitMetrics(diskPaths) {
@@ -1574,8 +1596,8 @@ var MonitorClient = class {
1574
1596
  const hostname = os.hostname();
1575
1597
  const cpuPercent = await this.measureCpuPercent(os);
1576
1598
  const memoryTotal = os.totalmem();
1577
- const memoryFree = os.freemem();
1578
- const memoryUsed = memoryTotal - memoryFree;
1599
+ const memoryAvailable = await this.getAvailableMemoryBytes(os, fs);
1600
+ const memoryUsed = memoryTotal - memoryAvailable;
1579
1601
  const memoryPercent = memoryTotal > 0 ? memoryUsed / memoryTotal * 100 : 0;
1580
1602
  const disks = await this.collectDiskMetrics(diskPaths, fs);
1581
1603
  await this.submitSystemMetric({
@@ -1591,12 +1613,13 @@ var MonitorClient = class {
1591
1613
  }
1592
1614
  }
1593
1615
  /**
1594
- * Measure CPU utilization by sampling cpus() twice with a 500ms gap.
1595
- * Returns a percentage (0–100).
1616
+ * Measure CPU utilization by sampling cpus() twice with a 3s gap.
1617
+ * The cumulative counters make this the average utilization over the
1618
+ * window, across all cores of the host. Returns a percentage (0–100).
1596
1619
  */
1597
1620
  async measureCpuPercent(os) {
1598
1621
  const sample1 = os.cpus();
1599
- await new Promise((resolve) => setTimeout(resolve, 500));
1622
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
1600
1623
  const sample2 = os.cpus();
1601
1624
  let totalIdle = 0;
1602
1625
  let totalTick = 0;
@@ -1608,9 +1631,30 @@ var MonitorClient = class {
1608
1631
  totalTick += currTotal - prevTotal;
1609
1632
  totalIdle += curr.times.idle - prev.times.idle;
1610
1633
  }
1611
- const idlePercent = totalTick > 0 ? totalIdle / totalTick * 100 : 0;
1634
+ if (totalTick <= 0) {
1635
+ return 0;
1636
+ }
1637
+ const idlePercent = totalIdle / totalTick * 100;
1612
1638
  return Math.max(0, Math.min(100, 100 - idlePercent));
1613
1639
  }
1640
+ /**
1641
+ * Get reclaimable memory in bytes. On Linux, reads MemAvailable from
1642
+ * /proc/meminfo so buffers/cache are not counted as used; falls back to
1643
+ * os.freemem() (MemFree) on other platforms or if parsing fails.
1644
+ */
1645
+ async getAvailableMemoryBytes(os, fs) {
1646
+ if (os.platform() === "linux") {
1647
+ try {
1648
+ const meminfo = await fs.readFile("/proc/meminfo", "utf8");
1649
+ const match = meminfo.match(/^MemAvailable:\s+(\d+)\s*kB$/m);
1650
+ if (match) {
1651
+ return Number(match[1]) * 1024;
1652
+ }
1653
+ } catch {
1654
+ }
1655
+ }
1656
+ return os.freemem();
1657
+ }
1614
1658
  /**
1615
1659
  * Collect disk usage for each configured path using fs.statfs() (Node 18.15+).
1616
1660
  */
package/dist/index.mjs CHANGED
@@ -508,6 +508,45 @@ var MonitorClient = class {
508
508
  clearTimeout(timeoutId);
509
509
  }
510
510
  }
511
+ /**
512
+ * Perform an HTTPS request with TLS certificate verification disabled.
513
+ * Used for health checks on servers with self-signed certificates.
514
+ * Uses Node.js built-in `https` module — works reliably in bundled environments.
515
+ */
516
+ async fetchInsecureHttps(url, options, timeoutMs) {
517
+ const https = await import("https");
518
+ const parsed = new URL(url);
519
+ return new Promise((resolve, reject) => {
520
+ let req;
521
+ const timeoutId = setTimeout(() => {
522
+ req?.destroy();
523
+ reject(new Error(`Request timeout after ${timeoutMs}ms`));
524
+ }, timeoutMs);
525
+ req = https.request(
526
+ {
527
+ hostname: parsed.hostname,
528
+ port: parsed.port || 443,
529
+ path: parsed.pathname + parsed.search,
530
+ method: options.method || "GET",
531
+ headers: options.headers,
532
+ rejectUnauthorized: false
533
+ },
534
+ (res) => {
535
+ clearTimeout(timeoutId);
536
+ res.resume();
537
+ resolve({ status: res.statusCode || 0 });
538
+ }
539
+ );
540
+ req.on("error", (err) => {
541
+ clearTimeout(timeoutId);
542
+ reject(err);
543
+ });
544
+ if (options.body) {
545
+ req.write(options.body);
546
+ }
547
+ req.end();
548
+ });
549
+ }
511
550
  async sendSingle(error) {
512
551
  const response = await this.fetchWithTimeout(`${this.endpoint}/api/v1/errors`, {
513
552
  method: "POST",
@@ -1312,24 +1351,7 @@ var MonitorClient = class {
1312
1351
  "Content-Type": "application/json"
1313
1352
  };
1314
1353
  }
1315
- if (endpoint.allowInsecureTls) {
1316
- try {
1317
- const undici = await import(
1318
- /* webpackIgnore: true */
1319
- "undici"
1320
- );
1321
- const Agent = undici.Agent;
1322
- requestOptions.dispatcher = new Agent({
1323
- connect: { rejectUnauthorized: false }
1324
- });
1325
- } catch {
1326
- }
1327
- }
1328
- const response = await this.fetchWithTimeout(
1329
- endpoint.url,
1330
- requestOptions,
1331
- endpoint.timeoutMs
1332
- );
1354
+ const response = endpoint.allowInsecureTls && endpoint.url.startsWith("https") ? await this.fetchInsecureHttps(endpoint.url, requestOptions, endpoint.timeoutMs) : await this.fetchWithTimeout(endpoint.url, requestOptions, endpoint.timeoutMs);
1333
1355
  const responseTimeMs = Date.now() - startTime;
1334
1356
  const statusCode = response.status;
1335
1357
  let status;
@@ -1510,7 +1532,7 @@ var MonitorClient = class {
1510
1532
  * Collect system metrics (CPU, RAM, disk) using built-in Node.js modules
1511
1533
  * and submit to the monitoring server.
1512
1534
  *
1513
- * Uses: os.cpus(), os.totalmem(), os.freemem(), os.hostname(), fs.statfs()
1535
+ * Uses: os.cpus(), os.totalmem(), /proc/meminfo (or os.freemem()), os.hostname(), fs.statfs()
1514
1536
  * Zero dependencies — all built-in Node.js 18.15+
1515
1537
  */
1516
1538
  async collectAndSubmitMetrics(diskPaths) {
@@ -1538,8 +1560,8 @@ var MonitorClient = class {
1538
1560
  const hostname = os.hostname();
1539
1561
  const cpuPercent = await this.measureCpuPercent(os);
1540
1562
  const memoryTotal = os.totalmem();
1541
- const memoryFree = os.freemem();
1542
- const memoryUsed = memoryTotal - memoryFree;
1563
+ const memoryAvailable = await this.getAvailableMemoryBytes(os, fs);
1564
+ const memoryUsed = memoryTotal - memoryAvailable;
1543
1565
  const memoryPercent = memoryTotal > 0 ? memoryUsed / memoryTotal * 100 : 0;
1544
1566
  const disks = await this.collectDiskMetrics(diskPaths, fs);
1545
1567
  await this.submitSystemMetric({
@@ -1555,12 +1577,13 @@ var MonitorClient = class {
1555
1577
  }
1556
1578
  }
1557
1579
  /**
1558
- * Measure CPU utilization by sampling cpus() twice with a 500ms gap.
1559
- * Returns a percentage (0–100).
1580
+ * Measure CPU utilization by sampling cpus() twice with a 3s gap.
1581
+ * The cumulative counters make this the average utilization over the
1582
+ * window, across all cores of the host. Returns a percentage (0–100).
1560
1583
  */
1561
1584
  async measureCpuPercent(os) {
1562
1585
  const sample1 = os.cpus();
1563
- await new Promise((resolve) => setTimeout(resolve, 500));
1586
+ await new Promise((resolve) => setTimeout(resolve, 3e3));
1564
1587
  const sample2 = os.cpus();
1565
1588
  let totalIdle = 0;
1566
1589
  let totalTick = 0;
@@ -1572,9 +1595,30 @@ var MonitorClient = class {
1572
1595
  totalTick += currTotal - prevTotal;
1573
1596
  totalIdle += curr.times.idle - prev.times.idle;
1574
1597
  }
1575
- const idlePercent = totalTick > 0 ? totalIdle / totalTick * 100 : 0;
1598
+ if (totalTick <= 0) {
1599
+ return 0;
1600
+ }
1601
+ const idlePercent = totalIdle / totalTick * 100;
1576
1602
  return Math.max(0, Math.min(100, 100 - idlePercent));
1577
1603
  }
1604
+ /**
1605
+ * Get reclaimable memory in bytes. On Linux, reads MemAvailable from
1606
+ * /proc/meminfo so buffers/cache are not counted as used; falls back to
1607
+ * os.freemem() (MemFree) on other platforms or if parsing fails.
1608
+ */
1609
+ async getAvailableMemoryBytes(os, fs) {
1610
+ if (os.platform() === "linux") {
1611
+ try {
1612
+ const meminfo = await fs.readFile("/proc/meminfo", "utf8");
1613
+ const match = meminfo.match(/^MemAvailable:\s+(\d+)\s*kB$/m);
1614
+ if (match) {
1615
+ return Number(match[1]) * 1024;
1616
+ }
1617
+ } catch {
1618
+ }
1619
+ }
1620
+ return os.freemem();
1621
+ }
1578
1622
  /**
1579
1623
  * Collect disk usage for each configured path using fs.statfs() (Node 18.15+).
1580
1624
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ceon-oy/monitor-sdk",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Client SDK for Ceon Monitor - Error tracking, health monitoring, security events, and vulnerability scanning",
5
5
  "author": "Ceon",
6
6
  "license": "MIT",