@blamejs/core 0.7.98 → 0.7.99

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.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
+
11
13
  - **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.
12
14
 
13
15
  - **0.7.97** (2026-05-06) — `b.compliance` lookup helpers. **`b.compliance.posturesByDomain(domain)`** returns every posture matching the named domain (`"privacy"` / `"health"` / `"payment"` / `"cybersecurity"` / `"financial-reporting"` / `"financial-resilience"` / `"product-cybersecurity"` / `"ai-governance"` / `"biometrics"` / `"audit-attestation"`). **`b.compliance.posturesByJurisdiction(jurisdiction)`** returns postures matching the ISO 3166 alpha-2 code, `EU`, or `international` — useful for multi-region deployments that resolve different posture configs per region. **`b.compliance.list()`** returns every posture as a `{ posture, name, citation, jurisdiction, domain }` row in canonical `KNOWN_POSTURES` order — admin UIs render the full set as a dropdown / table without iterating REGIME_MAP keys themselves. All three helpers are pure functions over the v0.7.94 REGIME_MAP and stay in sync with it as new postures land.
package/lib/db.js CHANGED
@@ -59,6 +59,7 @@ var dbSchema = require("./db-schema");
59
59
  var { defineClass } = require("./framework-error");
60
60
  var { boot } = require("./log");
61
61
  var lazyRequire = require("./lazy-require");
62
+ var observability = require("./observability");
62
63
  var ntpCheck = lazyRequire(function () { return require("./ntp-check"); });
63
64
  var safeAsync = require("./safe-async");
64
65
  var safeEnv = require("./parsers/safe-env");
@@ -1213,6 +1214,80 @@ module.exports = {
1213
1214
  // the snapshot source. Safe to call any time; no-op when no encPath
1214
1215
  // (plain mode) or when the plaintext DB doesn't exist.
1215
1216
  flushToDisk: encryptToDisk,
1217
+ // integrityCheck — runs PRAGMA integrity_check against the live db
1218
+ // and returns "ok" on success, an array of corruption lines
1219
+ // otherwise. Operators wire this into a periodic monitor or a
1220
+ // /healthz handler.
1221
+ integrityCheck: function () {
1222
+ _requireInit();
1223
+ var rows = database.prepare("PRAGMA integrity_check").all();
1224
+ if (rows.length === 1 && rows[0] && rows[0].integrity_check === "ok") return "ok";
1225
+ return rows.map(function (r) { return r && r.integrity_check; }).filter(Boolean);
1226
+ },
1227
+ // integrityMonitor — periodic PRAGMA integrity_check runner. Returns
1228
+ // a handle with .stop() for graceful shutdown. Audit emission on
1229
+ // every check; observability event on corruption.
1230
+ //
1231
+ // var mon = b.db.integrityMonitor({
1232
+ // intervalMs: C.TIME.hours(6),
1233
+ // onCorruption: function (issues) { /* operator hook — alerts */ },
1234
+ // });
1235
+ // ...
1236
+ // mon.stop();
1237
+ //
1238
+ // Audit emissions:
1239
+ // system.db.integrity_ok — every clean check
1240
+ // system.db.integrity_corrupt — corruption detected
1241
+ //
1242
+ // Observability event: db.integrity_check_ok counter on every clean
1243
+ // check, db.integrity_check_corrupt counter on corruption.
1244
+ integrityMonitor: function (opts) {
1245
+ _requireInit();
1246
+ opts = opts || {};
1247
+ var intervalMs = opts.intervalMs || C.TIME.hours(24);
1248
+ if (typeof intervalMs !== "number" || !isFinite(intervalMs) || intervalMs <= 0) {
1249
+ throw new TypeError("db.integrityMonitor: intervalMs must be a positive finite number");
1250
+ }
1251
+ var auditOn = opts.audit !== false;
1252
+
1253
+ function _tick() {
1254
+ var rows;
1255
+ try { rows = database.prepare("PRAGMA integrity_check").all(); }
1256
+ catch (_e) {
1257
+ try { observability.safeEvent("db.integrity_check_failed", 1, {}); }
1258
+ catch (_e2) { /* drop-silent */ }
1259
+ return;
1260
+ }
1261
+ var ok = rows.length === 1 && rows[0] && rows[0].integrity_check === "ok";
1262
+ if (ok) {
1263
+ try { observability.safeEvent("db.integrity_check_ok", 1, {}); }
1264
+ catch (_e) { /* drop-silent */ }
1265
+ if (auditOn) {
1266
+ try { audit.safeEmit({
1267
+ action: "system.db.integrity_ok", outcome: "ok", metadata: {},
1268
+ }); } catch (_e) { /* drop-silent */ }
1269
+ }
1270
+ return;
1271
+ }
1272
+ var issues = rows.map(function (r) { return r && r.integrity_check; }).filter(Boolean);
1273
+ try { observability.safeEvent("db.integrity_check_corrupt", 1, {}); }
1274
+ catch (_e) { /* drop-silent */ }
1275
+ if (auditOn) {
1276
+ try { audit.safeEmit({
1277
+ action: "system.db.integrity_corrupt", outcome: "fail",
1278
+ metadata: { issueCount: issues.length },
1279
+ }); } catch (_e) { /* drop-silent */ }
1280
+ }
1281
+ if (typeof opts.onCorruption === "function") {
1282
+ try { opts.onCorruption(issues); } catch (_e) { /* operator hook */ }
1283
+ }
1284
+ }
1285
+
1286
+ var handle = safeAsync.repeating(_tick, intervalMs, { name: "db-integrity-monitor" });
1287
+ return {
1288
+ stop: function () { if (handle) { handle.stop(); handle = null; } },
1289
+ };
1290
+ },
1216
1291
  // purgeAuditChain — narrow-purpose DELETE for audit-tools.purge.
1217
1292
  // Drops the BEFORE-DELETE append-only trigger inside a transaction,
1218
1293
  // executes the deletion, then re-installs the trigger so the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.7.98",
3
+ "version": "0.7.99",
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:387ca63b-9d87-46d5-a7a5-ff7e577e0bd3",
5
+ "serialNumber": "urn:uuid:a1c08980-f218-4272-8ccc-742e21f943c1",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-06T09:03:18.727Z",
8
+ "timestamp": "2026-05-06T09:14:16.202Z",
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.98",
22
+ "bom-ref": "@blamejs/core@0.7.99",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.7.98",
25
+ "version": "0.7.99",
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.98",
29
+ "purl": "pkg:npm/%40blamejs/core@0.7.99",
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.98",
57
+ "ref": "@blamejs/core@0.7.99",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]