@blamejs/core 0.7.101 → 0.7.102

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.102** (2026-05-06) — `b.middleware.tracePropagate({ generateIfMissing, ... })` — middleware that consumes the inbound `traceparent` header per W3C Trace Context and stamps `req.trace = { traceId, parentId, sampled, hadUpstream }` for downstream handlers + propagation into outbound HTTP calls. `generateIfMissing: true` (default) synthesises a fresh trace when the inbound header is missing/malformed and stamps `hadUpstream: false`. `auditOnMissing: true` emits `system.trace.synthesised` audit events on every locally-originated trace. `setResponseHeader: true` echoes the resolved traceparent on the response (useful when the framework is the back-end of an L7 router that wants to log it). Composes with `b.observability.traceContext` (v0.7.101) for outbound propagation: downstream handlers read `req.trace.traceId` and pass it to `traceContext.build({ traceId: req.trace.traceId, parentId: traceContext.newParentId(), sampled: req.trace.sampled })` for the `traceparent` header on upstream calls.
12
+
11
13
  - **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
14
 
13
15
  - **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.
@@ -46,6 +46,7 @@ var requireMethods = require("./require-methods");
46
46
  var securityHeaders = require("./security-headers");
47
47
  var securityTxt = require("./security-txt");
48
48
  var sse = require("./sse");
49
+ var tracePropagate = require("./trace-propagate");
49
50
  var tusUpload = require("./tus-upload");
50
51
  var webAppManifest = require("./web-app-manifest");
51
52
 
@@ -80,6 +81,7 @@ module.exports = {
80
81
  dpop: dpop.create,
81
82
  hostAllowlist: hostAllowlist.create,
82
83
  networkAllowlist: networkAllowlist.create,
84
+ tracePropagate: tracePropagate.create,
83
85
  tusUpload: tusUpload.create,
84
86
  webAppManifest: webAppManifest.create,
85
87
 
@@ -112,6 +114,7 @@ module.exports = {
112
114
  dpop: dpop,
113
115
  hostAllowlist: hostAllowlist,
114
116
  networkAllowlist: networkAllowlist,
117
+ tracePropagate: tracePropagate,
115
118
  tusUpload: tusUpload,
116
119
  webAppManifest: webAppManifest,
117
120
  },
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ /**
3
+ * trace-propagate middleware — consumes the inbound `traceparent`
4
+ * header per W3C Trace Context (https://www.w3.org/TR/trace-context-1/)
5
+ * and stamps `req.trace = { traceId, parentId, sampled, hadUpstream }`
6
+ * for downstream handlers + propagation into outbound HTTP calls.
7
+ *
8
+ * router.use(b.middleware.tracePropagate({
9
+ * generateIfMissing: true, // default — synthesise when absent
10
+ * auditOnMissing: true, // emit `system.trace.synthesised` event
11
+ * setResponseHeader: true, // echo the resolved traceparent on res
12
+ * }));
13
+ *
14
+ * app.get("/widgets", function (req, res) {
15
+ * // req.trace.traceId is the canonical id for this request
16
+ * b.observability.event("widgets.request", 1, {
17
+ * [b.observability.SEMCONV.HTTP_REQUEST_METHOD]: req.method,
18
+ * });
19
+ * // Propagate to an upstream call:
20
+ * fetch(upstreamUrl, {
21
+ * headers: {
22
+ * traceparent: b.observability.traceContext.build({
23
+ * traceId: req.trace.traceId,
24
+ * parentId: b.observability.traceContext.newParentId(),
25
+ * sampled: req.trace.sampled,
26
+ * }),
27
+ * },
28
+ * });
29
+ * });
30
+ *
31
+ * On bad / missing inbound traceparent:
32
+ * - generateIfMissing: true (default) → synthesise a fresh trace,
33
+ * stamp `hadUpstream: false` so downstream code knows this trace
34
+ * was originated locally
35
+ * - generateIfMissing: false → leave `req.trace = null`; downstream
36
+ * code that depends on a trace MUST handle the null case
37
+ */
38
+
39
+ var lazyRequire = require("../lazy-require");
40
+ var validateOpts = require("../validate-opts");
41
+ var { defineClass } = require("../framework-error");
42
+
43
+ var TracePropagateError = defineClass("TracePropagateError", { alwaysPermanent: true });
44
+
45
+ var observability = lazyRequire(function () { return require("../observability"); });
46
+ var audit = lazyRequire(function () { return require("../audit"); });
47
+
48
+ function create(opts) {
49
+ opts = opts || {};
50
+ validateOpts(opts, [
51
+ "generateIfMissing", "auditOnMissing",
52
+ "setResponseHeader", "audit",
53
+ ], "middleware.tracePropagate");
54
+
55
+ var generateIfMissing = opts.generateIfMissing !== false; // default true
56
+ var auditOnMissing = opts.auditOnMissing === true; // default false (every request that doesn't carry a trace is noisy)
57
+ var setResponseHeader = opts.setResponseHeader === true; // default false
58
+ var auditOn = opts.audit !== false;
59
+
60
+ return function tracePropagateMiddleware(req, res, next) {
61
+ var tc = observability().traceContext;
62
+ var inbound = req.headers && req.headers.traceparent;
63
+ var parsed = (typeof inbound === "string") ? tc.parse(inbound) : null;
64
+ if (parsed) {
65
+ req.trace = {
66
+ traceId: parsed.traceId,
67
+ parentId: parsed.parentId,
68
+ sampled: parsed.sampled,
69
+ hadUpstream: true,
70
+ };
71
+ } else if (generateIfMissing) {
72
+ req.trace = {
73
+ traceId: tc.newTraceId(),
74
+ parentId: tc.newParentId(),
75
+ sampled: true,
76
+ hadUpstream: false,
77
+ };
78
+ if (auditOnMissing && auditOn) {
79
+ try {
80
+ audit().safeEmit({
81
+ action: "system.trace.synthesised",
82
+ outcome: "ok",
83
+ metadata: { route: req.url || "/", traceId: req.trace.traceId },
84
+ });
85
+ } catch (_e) { /* drop-silent — observability sink */ }
86
+ }
87
+ } else {
88
+ req.trace = null;
89
+ }
90
+
91
+ if (setResponseHeader && req.trace && !res.headersSent) {
92
+ try {
93
+ res.setHeader("traceparent", tc.build({
94
+ traceId: req.trace.traceId,
95
+ parentId: req.trace.parentId,
96
+ sampled: req.trace.sampled,
97
+ }));
98
+ } catch (_e) { /* drop-silent — header set best-effort */ }
99
+ }
100
+ return next();
101
+ };
102
+ }
103
+
104
+ module.exports = {
105
+ create: create,
106
+ TracePropagateError: TracePropagateError,
107
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.7.101",
3
+ "version": "0.7.102",
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:a1fc9374-766f-4ee8-8a57-d02b5e754ce5",
5
+ "serialNumber": "urn:uuid:4b25a892-26de-481b-9c07-1e2612710dd0",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-06T09:42:14.464Z",
8
+ "timestamp": "2026-05-06T09:52:45.058Z",
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.101",
22
+ "bom-ref": "@blamejs/core@0.7.102",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.7.101",
25
+ "version": "0.7.102",
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.101",
29
+ "purl": "pkg:npm/%40blamejs/core@0.7.102",
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.101",
57
+ "ref": "@blamejs/core@0.7.102",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]