@blamejs/core 0.7.100 → 0.7.101

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.101** (2026-05-06) — `b.observability.traceContext` — W3C Trace Context (https://www.w3.org/TR/trace-context-1/) parser + builder. **`traceContext.parse(headerValue)`** consumes a `traceparent` HTTP header value (`00-<32hex traceId>-<16hex parentId>-<2hex flags>`) and returns `{ version, traceId, parentId, flags, sampled }` or null on malformed input. Enforces the §3.2.2.3 / §3.2.2.4 all-zero-rejection rule (zero trace-id and zero parent-id are explicitly forbidden by spec). **`traceContext.build({ traceId, parentId, sampled })`** produces a v1 `traceparent` header value; throws on bad input shape. **`traceContext.newTraceId()` / `newParentId()`** generate fresh randomized 128-bit / 64-bit hex strings (with the all-zero retry path the spec requires). Operators wiring distributed tracing across services use these to propagate trace IDs across an outbound HTTP call without a vendored OTel SDK — pair with the SEMCONV constants from v0.7.95 to build OTel-aligned spans on top.
12
+
11
13
  - **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
14
 
13
15
  - **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.
@@ -312,11 +312,87 @@ var SEMCONV = Object.freeze({
312
312
  K8S_DEPLOYMENT_NAME: "k8s.deployment.name",
313
313
  });
314
314
 
315
+ // W3C Trace Context — parse / build the `traceparent` HTTP header
316
+ // per https://www.w3.org/TR/trace-context-1/. Operators wiring
317
+ // distributed tracing across services use these to propagate the
318
+ // trace ID across an outbound HTTP call without a vendored OTel SDK.
319
+ //
320
+ // Format: `<version>-<trace-id>-<parent-id>-<trace-flags>`
321
+ // version: 2 hex chars; "00" for v1
322
+ // trace-id: 32 hex chars (128 bits); MUST be all-zero-rejected
323
+ // parent-id: 16 hex chars (64 bits); MUST be all-zero-rejected
324
+ // trace-flags: 2 hex chars; bit 0 = sampled
325
+ var _TRACEPARENT_RE = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;
326
+ var _ALL_ZERO_TRACE = "00000000000000000000000000000000";
327
+ var _ALL_ZERO_PARENT = "0000000000000000";
328
+
329
+ var _HEX_RADIX = 16; // allow:raw-byte-literal — Number.parseInt radix
330
+ var _TRACE_FLAG_SAMPLED = 0x01; // W3C Trace Context §3.2.2.5 sampled bit
331
+ var _TRACE_ID_BYTES = 16; // allow:raw-byte-literal — W3C Trace Context §3.2.2.3 (16 bytes)
332
+ var _PARENT_ID_BYTES = 8; // allow:raw-byte-literal — W3C Trace Context §3.2.2.4 (8 bytes)
333
+ var _FLAGS_HEX_LEN = 2; // allow:raw-byte-literal — W3C Trace Context flags are 1 byte = 2 hex chars
334
+
335
+ function _parseTraceparent(headerValue) {
336
+ if (typeof headerValue !== "string" || headerValue.length === 0) return null;
337
+ var s = headerValue.trim().toLowerCase();
338
+ var m = s.match(_TRACEPARENT_RE);
339
+ if (!m) return null;
340
+ if (m[2] === _ALL_ZERO_TRACE) return null; // §3.2.2.3 — trace-id MUST NOT be zero
341
+ if (m[3] === _ALL_ZERO_PARENT) return null; // §3.2.2.4 — parent-id MUST NOT be zero
342
+ var flagsByte = parseInt(m[4], _HEX_RADIX);
343
+ return {
344
+ version: m[1],
345
+ traceId: m[2],
346
+ parentId: m[3],
347
+ flags: m[4],
348
+ sampled: (flagsByte & _TRACE_FLAG_SAMPLED) === _TRACE_FLAG_SAMPLED,
349
+ };
350
+ }
351
+
352
+ function _buildTraceparent(opts) {
353
+ if (!opts || typeof opts !== "object" || Array.isArray(opts)) {
354
+ throw new TypeError("traceContext.build: opts must be a plain object");
355
+ }
356
+ var traceId = opts.traceId;
357
+ var parentId = opts.parentId;
358
+ if (typeof traceId !== "string" || !/^[0-9a-f]{32}$/.test(traceId) || traceId === _ALL_ZERO_TRACE) {
359
+ throw new TypeError("traceContext.build: traceId must be 32 lowercase hex chars (non-zero)");
360
+ }
361
+ if (typeof parentId !== "string" || !/^[0-9a-f]{16}$/.test(parentId) || parentId === _ALL_ZERO_PARENT) {
362
+ throw new TypeError("traceContext.build: parentId must be 16 lowercase hex chars (non-zero)");
363
+ }
364
+ var flagsByte = (opts.sampled ? _TRACE_FLAG_SAMPLED : 0);
365
+ var flags = flagsByte.toString(_HEX_RADIX).padStart(_FLAGS_HEX_LEN, "0");
366
+ return "00-" + traceId + "-" + parentId + "-" + flags;
367
+ }
368
+
369
+ var _nodeCryptoForTrace = require("crypto");
370
+
371
+ function _newTraceId() {
372
+ var hex = _nodeCryptoForTrace.randomBytes(_TRACE_ID_BYTES).toString("hex");
373
+ // Zero-trace-id is forbidden per spec; in the astronomically unlikely
374
+ // case rand returned all-zero, retry once.
375
+ return hex === _ALL_ZERO_TRACE ? _nodeCryptoForTrace.randomBytes(_TRACE_ID_BYTES).toString("hex") : hex;
376
+ }
377
+
378
+ function _newParentId() {
379
+ var hex = _nodeCryptoForTrace.randomBytes(_PARENT_ID_BYTES).toString("hex");
380
+ return hex === _ALL_ZERO_PARENT ? _nodeCryptoForTrace.randomBytes(_PARENT_ID_BYTES).toString("hex") : hex;
381
+ }
382
+
383
+ var traceContext = {
384
+ parse: _parseTraceparent,
385
+ build: _buildTraceparent,
386
+ newTraceId: _newTraceId,
387
+ newParentId: _newParentId,
388
+ };
389
+
315
390
  module.exports = {
316
- tap: tap,
317
- event: event,
318
- safeEvent: safeEvent,
319
- timed: timed,
320
- setTap: setTap,
321
- SEMCONV: SEMCONV,
391
+ tap: tap,
392
+ event: event,
393
+ safeEvent: safeEvent,
394
+ timed: timed,
395
+ setTap: setTap,
396
+ SEMCONV: SEMCONV,
397
+ traceContext: traceContext,
322
398
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.7.100",
3
+ "version": "0.7.101",
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:41d841af-2890-4424-89ab-7b411b784c39",
5
+ "serialNumber": "urn:uuid:a1fc9374-766f-4ee8-8a57-d02b5e754ce5",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-06T09:26:08.410Z",
8
+ "timestamp": "2026-05-06T09:42:14.464Z",
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.100",
22
+ "bom-ref": "@blamejs/core@0.7.101",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.7.100",
25
+ "version": "0.7.101",
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.100",
29
+ "purl": "pkg:npm/%40blamejs/core@0.7.101",
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.100",
57
+ "ref": "@blamejs/core@0.7.101",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]