@blamejs/core 0.7.99 → 0.7.100

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/CHANGELOG.md CHANGED
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.7.x
10
10
 
11
+ - **0.7.100** (2026-05-06) — `b.network.tls.expiryMonitor({ intervalMs, windowMs, onExpiring })` — periodic CA-trust-store expiry monitor. Runs `expiringSoon(windowMs)` on a schedule; emits `network.tls.ca.expiry_check` audit event on every check (with `expiring` count + `total` CA count), `network.tls.ca.expiring` audit event when any CA falls inside the window, and the matching `network.tls.ca.expiring` observability counter. Optional `onExpiring(rows)` operator hook fires on every check that surfaces expiring CAs so operators can wire pager / Slack alerts. Audit metadata captures the expiring CA labels + the earliest `validTo` timestamp so dashboards can compute "days until first expiry" without re-querying. Returns a handle with `.stop()` for graceful shutdown. Closes the v0.7.26 OCSP/CT batch's continuous-trust-monitoring follow-up.
12
+
11
13
  - **0.7.99** (2026-05-06) — `b.db.integrityCheck()` + `b.db.integrityMonitor({ intervalMs, ... })` — periodic SQLite corruption detection. **`b.db.integrityCheck()`** runs `PRAGMA integrity_check` against the live database and returns `"ok"` on a healthy database, or an array of corruption description strings on damage. Operators wire this into `/healthz` handlers or one-off CLI checks. **`b.db.integrityMonitor({ intervalMs, onCorruption })`** runs the check on a schedule (24h default), emits `system.db.integrity_ok` / `system.db.integrity_corrupt` audit events, and fires the `db.integrity_check_ok` / `db.integrity_check_corrupt` observability counters. Optional `onCorruption(issues)` operator hook fires on every corrupt-result so operators can wire pager alerts. The previous boot-time-only integrity check (added in v0.7.79) continues to run unchanged at db.init; the monitor is for long-running deployments where filesystem-level corruption can develop after boot. Returns a handle with `.stop()` for graceful shutdown.
12
14
 
13
15
  - **0.7.98** (2026-05-06) — `b.ntpCheck.monitor({ intervalMs, ... })` — periodic clock-drift monitor that runs `checkDrift` on a schedule and emits audit + observability events on threshold crossings. Returns a handle with `.stop()` for graceful shutdown. Audit emissions: `system.ntp.checked` (every check), `system.ntp.drift_warn` (drift exceeds warn threshold), `system.ntp.drift_fatal` (drift exceeds fatal threshold), `system.ntp.unreachable` (every server in the list failed to respond). Observability event: `ntp.drift_ms` gauge on every successful check, labeled with the responding server. Optional `onDrift(result)` operator hook fires on every warning/fatal check so operators can wire pager / Slack notifications. The previous boot-time-only `b.ntpCheck.bootCheck` continues to run unchanged at db.init; the monitor is for long-running deployments where clock-drift can develop after boot (container with no RTC sync, ntpd stopped after boot, etc.). Closes the v0.7.79 audit-batch slice for continuous time integrity.
@@ -9,6 +9,7 @@ var C = require("./constants");
9
9
  var safeBuffer = require("./safe-buffer");
10
10
  var validateOpts = require("./validate-opts");
11
11
  var lazyRequire = require("./lazy-require");
12
+ var safeAsync = require("./safe-async");
12
13
  var { defineClass } = require("./framework-error");
13
14
 
14
15
  var TlsTrustError = defineClass("TlsTrustError", { alwaysPermanent: true });
@@ -248,6 +249,82 @@ function expiringSoon(windowMs) {
248
249
  });
249
250
  }
250
251
 
252
+ // expiryMonitor — periodic check that emits audit + observability
253
+ // events when any CA in the trust store falls inside the expiry
254
+ // window. Returns a handle with .stop() for graceful shutdown.
255
+ //
256
+ // var mon = b.network.tls.expiryMonitor({
257
+ // intervalMs: C.TIME.hours(6),
258
+ // windowMs: C.TIME.days(30),
259
+ // onExpiring: function (rows) { /* operator hook — alerts */ },
260
+ // });
261
+ // ...
262
+ // mon.stop();
263
+ //
264
+ // Audit emissions:
265
+ // network.tls.ca.expiry_check — every check, reports total + expiring count
266
+ // network.tls.ca.expiring — when expiringSoon(windowMs) > 0
267
+ //
268
+ // Observability event: network.tls.ca.expiring counter labeled with
269
+ // the count.
270
+ function expiryMonitor(opts) {
271
+ opts = opts || {};
272
+ var intervalMs = opts.intervalMs;
273
+ var windowMs = opts.windowMs;
274
+ var auditOn = opts.audit !== false;
275
+ if (typeof intervalMs !== "number" || !isFinite(intervalMs) || intervalMs <= 0) {
276
+ throw new TlsTrustError("tls/bad-interval",
277
+ "tls.expiryMonitor: intervalMs must be a positive finite number");
278
+ }
279
+ if (typeof windowMs !== "number" || !isFinite(windowMs) || windowMs <= 0) {
280
+ throw new TlsTrustError("tls/bad-window",
281
+ "tls.expiryMonitor: windowMs must be a positive finite number");
282
+ }
283
+
284
+ function _tick() {
285
+ var rows;
286
+ try { rows = expiringSoon(windowMs); }
287
+ catch (_e) { return; }
288
+ if (auditOn) {
289
+ try {
290
+ audit().safeEmit({
291
+ action: "network.tls.ca.expiry_check",
292
+ outcome: rows.length > 0 ? "warn" : "ok",
293
+ metadata: { total: STATE.cas.length, expiring: rows.length, windowMs: windowMs },
294
+ });
295
+ } catch (_e) { /* drop-silent */ }
296
+ }
297
+ if (rows.length > 0) {
298
+ try { observability().safeEvent("network.tls.ca.expiring", rows.length, {}); }
299
+ catch (_e) { /* drop-silent */ }
300
+ if (auditOn) {
301
+ try {
302
+ audit().safeEmit({
303
+ action: "network.tls.ca.expiring",
304
+ outcome: "warn",
305
+ metadata: {
306
+ count: rows.length,
307
+ labels: rows.map(function (r) { return r.label; }),
308
+ earliestValidTo: rows.reduce(function (acc, r) {
309
+ var ms = r.validTo ? Date.parse(r.validTo) : Infinity;
310
+ return ms < acc ? ms : acc;
311
+ }, Infinity),
312
+ },
313
+ });
314
+ } catch (_e) { /* drop-silent */ }
315
+ }
316
+ if (typeof opts.onExpiring === "function") {
317
+ try { opts.onExpiring(rows); } catch (_e) { /* operator hook */ }
318
+ }
319
+ }
320
+ }
321
+
322
+ var handle = safeAsync.repeating(_tick, intervalMs, { name: "tls-expiry-monitor" });
323
+ return {
324
+ stop: function () { if (handle) { handle.stop(); handle = null; } },
325
+ };
326
+ }
327
+
251
328
  function captureBaselineFingerprints() {
252
329
  STATE.baselineFingerprints = STATE.cas.map(function (e) { return e.meta.fingerprint256; });
253
330
  }
@@ -1557,6 +1634,7 @@ module.exports = {
1557
1634
  clearAll: clearAll,
1558
1635
  purgeExpired: purgeExpired,
1559
1636
  expiringSoon: expiringSoon,
1637
+ expiryMonitor: expiryMonitor,
1560
1638
  useSystemTrust: useSystemTrust,
1561
1639
  isSystemTrustEnabled: isSystemTrustEnabled,
1562
1640
  getTrustStore: getTrustStore,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.7.99",
3
+ "version": "0.7.100",
4
4
  "description": "The Node framework that owns its stack.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:a1c08980-f218-4272-8ccc-742e21f943c1",
5
+ "serialNumber": "urn:uuid:41d841af-2890-4424-89ab-7b411b784c39",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-06T09:14:16.202Z",
8
+ "timestamp": "2026-05-06T09:26:08.410Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/core@0.7.99",
22
+ "bom-ref": "@blamejs/core@0.7.100",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.7.99",
25
+ "version": "0.7.100",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "The Node framework that owns its stack.",
29
- "purl": "pkg:npm/%40blamejs/core@0.7.99",
29
+ "purl": "pkg:npm/%40blamejs/core@0.7.100",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/core@0.7.99",
57
+ "ref": "@blamejs/core@0.7.100",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]