@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 +2 -0
- package/lib/middleware/index.js +3 -0
- package/lib/middleware/trace-propagate.js +107 -0
- package/package.json +1 -1
- package/sbom.cyclonedx.json +6 -6
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.
|
package/lib/middleware/index.js
CHANGED
|
@@ -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
package/sbom.cyclonedx.json
CHANGED
|
@@ -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:
|
|
5
|
+
"serialNumber": "urn:uuid:4b25a892-26de-481b-9c07-1e2612710dd0",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-06T09:
|
|
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.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.7.102",
|
|
23
23
|
"type": "library",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.7.
|
|
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.
|
|
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.
|
|
57
|
+
"ref": "@blamejs/core@0.7.102",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|