@blamejs/core 0.15.29 → 0.15.31
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 +4 -0
- package/lib/compliance.js +1 -1
- package/lib/db-file-lifecycle.js +1 -1
- package/lib/guard-list-id.js +1 -1
- package/lib/log.js +1 -1
- package/lib/mail-crypto-pgp.js +1 -1
- package/lib/middleware/span-http-server.js +2 -2
- package/lib/static.js +3 -3
- package/lib/vendor-data.js +1 -1
- package/lib/watcher.js +1 -1
- package/lib/webhook-dispatcher.js +6 -2
- package/lib/webhook.js +22 -8
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,10 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.15.x
|
|
10
10
|
|
|
11
|
+
- v0.15.31 (2026-06-26) — **Internal test-suite hardening only — the published library's runtime behavior and public API are unchanged (source-comment marker text aside).** The codebase-patterns guard suite gains a gate that retires a renamed suppression-marker token: once a suppression class is re-verified and renamed, its old token cannot be silently re-registered, so a later suppression has to be re-examined under the new name instead of inheriting a stale approval. Eight suppression classes were re-verified and renamed to descriptive tokens this release, and their in-source marker comments were updated to match. No runtime code, public API, or wire format changed. **Detectors:** *Re-verification gate retires a renamed suppression-marker token* — A new guard refuses to re-register a retired suppression-marker token, and the orphan check points a stale marker at its current name. When a suppression class is re-verified, it is renamed to a descriptive token and the old name is recorded as retired, so the old approval cannot be quietly resurrected — a future suppression must be re-examined and re-stamped under the new name. This is test-suite tooling; no shipped framework behavior changed.
|
|
12
|
+
|
|
13
|
+
- v0.15.30 (2026-06-26) — **Importing the webhook module for inbound signature verification no longer pulls the Node HTTP client (or its `node:http` / `node:https` / `node:http2` chain), so `b.webhook.verify` runs in a Worker / edge runtime when the module is imported directly.** lib/webhook and its delivery store eagerly required the outbound HTTP client at module load — directly, and transitively through the persistence-backed dispatcher — so importing the webhook module threw in a Cloudflare Workers / edge runtime that has no node:http / node:net / node:tls, even though b.webhook.verify needs only HMAC-SHA-256 and a timing-safe compare. The HTTP client and the SQL-backed dispatcher are now resolved lazily, only on the outbound send / dispatch paths; importing the module for inbound verification loads no Node networking module. Verified by asserting no networking builtin appears in process.moduleLoadList on the verify path. The framework's aggregate entry point still initializes the networking stack eagerly, so the edge verify path is the webhook module imported directly rather than the aggregate b namespace. **Fixed:** *Inbound webhook verification loads without the Node networking stack (Worker / edge runtime)* — The webhook module and its dispatcher delivery store required the outbound HTTP client (node:http / node:https / node:http2) at module load, so importing the module threw in a runtime without those builtins — even though b.webhook.verify is HMAC-SHA-256 plus a timing-safe compare and the dispatcher (SQL-backed persistence) is only needed for outbound delivery. The HTTP client and the dispatcher are now resolved lazily, on the outbound send / dispatch paths only; the inbound verify path loads no Node networking module. An edge handler that imports the webhook module directly can pre-verify an inbound Stripe webhook signature with the primitive's hardening (Stripe-Signature size cap, v1-hex anti-DoS cap, minimum-tolerance floor, optional atomic replay store) instead of hand-rolling the t=/v1= parse, tolerance window, and timing-safe compare. The framework's aggregate entry still loads the networking stack eagerly; import the webhook module directly for the edge verify path.
|
|
14
|
+
|
|
11
15
|
- v0.15.29 (2026-06-25) — **JSON parsing of operator and untrusted input is routed through `b.safeJson` everywhere, so a `"__proto__"` member is stripped and the parse is size-bounded — `b.openapi.parse`, `b.asyncapi.parse`, and `b.sandbox.run` were using a raw `JSON.parse`.** b.openapi.parse and b.asyncapi.parse parsed an operator-supplied document string with a raw JSON.parse, which re-creates a "__proto__" member as an own key and imposes no size bound; b.sandbox.run parsed the untrusted sandboxed code's serialized result the same way (proto member kept, depth unbounded). All three now route through b.safeJson, which strips the prototype-pollution keys and applies the depth / key / size caps. A new b.safeJson.parseStringOrObject primitive captures the recurring "accept a document as a JSON string OR a pre-built object" shape (a string is parsed safely, an object passes through) that openapi and asyncapi had each hand-rolled, with each consumer's typed error class and a generous document size cap passed as data. Valid input parses identically to before; a malicious or oversized document is now defused rather than accepted. **Added:** *b.safeJson.parseStringOrObject(input, opts?)* — Accepts either a JSON string — parsed through b.safeJson.parse, so the prototype-pollution-key strip and depth / key / size caps apply — or an already-decoded plain object (returned unchanged). For the recurring "operator hands me a document as a JSON string or a pre-built object" surface (b.openapi / b.asyncapi). The consumer's typed error class, error codes, label, and size cap are passed as options, so a raw JSON.parse on operator input cannot be hand-rolled per consumer. **Security:** *Operator and untrusted JSON parses strip __proto__ and bound size (no raw JSON.parse)* — A raw JSON.parse keeps a "__proto__" object member as an own key (a prototype-pollution gadget for any downstream merge) and parses unbounded input. b.openapi.parse and b.asyncapi.parse used it on operator document strings, and b.sandbox.run used it on the untrusted sandboxed code's JSON-serialized result. All now route through b.safeJson — the prototype-pollution keys are stripped and the depth / key / size caps apply (a 16 MiB document cap for openapi/asyncapi, the existing result-bytes cap for the sandbox). Internal JSON parses (the sealed DSR store payloads, the VEX canonical re-format) route through the same primitive too, so the guarantee cannot be bypassed one call site at a time. Valid input is unaffected; a "__proto__"-laden or oversized payload is defused.
|
|
12
16
|
|
|
13
17
|
- v0.15.28 (2026-06-25) — **`b.network.dns` and `b.network.tls` errors now carry a usable terminal-vs-transient signal on `err.permanent`, so a caller's retry loop re-attempts only the failures a retry can fix.** DnsError was declared always-transient and NetworkTlsError always-permanent, so a consumer driving its own retry loop got the wrong signal in both directions: it would retry a permanent DNS failure (a bad host, bad options, an unsupported query, an NXDOMAIN-style no-result, or a caller-shape/config error such as an unconfigured transport or an invalid resolver list) forever, and it would refuse to retry a transient TLS-over-network failure (an ECH connection failure, a handshake timeout, DNS momentarily unavailable). err.permanent now reflects each error's actual transience, derived from its code and failing closed (an unknown code is permanent, so a hopeless target is not retried indefinitely): for DnsError only a failed network round-trip (a lookup timeout, a resolve/reverse query that failed on the wire, a failed DoH/DoT exchange, a DDR discovery that found nothing) is transient — config, input, and environment errors raised before any network work are permanent; for NetworkTlsError only the network-layer ECH failures are transient. TlsTrustError remains always-permanent by design — a trust-verification failure (bad CA, fingerprint mismatch, OCSP not-good, CT violation, an unreachable OCSP responder) must never be silently retried past the trust decision. **Fixed:** *DnsError / NetworkTlsError expose a correct terminal/transient signal; TlsTrustError stays terminal* — b.network.dns's DnsError was always-transient and b.network.tls's NetworkTlsError always-permanent, so err.permanent misled a consumer's retry loop in both directions — retrying a permanent DNS error (bad host / options / unsupported type / no-result) indefinitely, and never retrying a transient TLS network error (ECH connect failure, handshake timeout, DNS unavailable). err.permanent now reflects each error's actual transience by code and fails closed (unknown codes are permanent): DnsError is transient only for a failed network round-trip (dns/lookup-timeout, dns/resolve-failed, dns/reverse-failed, dns/doh-failed, dns/dot-failed, dns/dot-handshake-failed, dns/ddr-not-discovered, dns/system-failed), and permanent otherwise — including the caller-shape / environment errors raised before any network work (dns/transport-unavailable for an unconfigured transport, dns/dnr-no-resolvers for an empty/invalid resolver list, dns/setservers-failed for an invalid address, dns/no-system-resolvers when none are configured). NetworkTlsError is transient only for the network-layer ECH failures (tls/ech-connect-failed, tls/ech-timeout, tls/ech-dns-unavailable), permanent otherwise. TlsTrustError remains always-permanent so a trust-verification failure is never silently retried.
|
package/lib/compliance.js
CHANGED
|
@@ -443,7 +443,7 @@ function set(posture) {
|
|
|
443
443
|
// guaranteed). Pure signal — no behavior change.
|
|
444
444
|
var REGULATED = ["hipaa", "pci-dss", "sox", "gdpr", "soc2", "fda-21cfr11"];
|
|
445
445
|
if (REGULATED.indexOf(posture) !== -1) {
|
|
446
|
-
var tz = process.env.TZ; // allow:raw-process-env — bootstrap signal, no operator-supplied default needed
|
|
446
|
+
var tz = process.env.TZ; // allow:raw-process-env-bootstrap — bootstrap signal, no operator-supplied default needed
|
|
447
447
|
if (typeof tz === "string" && tz !== "UTC" && tz !== "Etc/UTC") {
|
|
448
448
|
_emitAudit("compliance.posture.tz_warning",
|
|
449
449
|
{ posture: posture, tz: tz, recommendation: "Set TZ=UTC under regulated postures so audit timestamps align with regulator expectations." },
|
package/lib/db-file-lifecycle.js
CHANGED
|
@@ -288,7 +288,7 @@ function fileLifecycle(opts) {
|
|
|
288
288
|
"fileLifecycle.startFlushTimer: timer already running — call stop() first");
|
|
289
289
|
}
|
|
290
290
|
var interval = sopts.intervalMs || flushIntervalMs;
|
|
291
|
-
encTimer = setInterval(function () { // allow:timer-no-unref — .unref() called immediately below; timer doesn't pin the event loop
|
|
291
|
+
encTimer = setInterval(function () { // allow:timer-no-unref-unrefed-below — .unref() called immediately below; timer doesn't pin the event loop
|
|
292
292
|
try { flushNow(db); }
|
|
293
293
|
catch (e) {
|
|
294
294
|
_emitAudit("flush_failed", "failure", {
|
package/lib/guard-list-id.js
CHANGED
|
@@ -242,7 +242,7 @@ function validate(headerValue, opts) {
|
|
|
242
242
|
// so a `localhost.` label-suffix is already refused at the segment-
|
|
243
243
|
// shape level (an empty trailing segment fails the dot-atom-text
|
|
244
244
|
// grammar). No trailing-dot bypass surface here.
|
|
245
|
-
var isLocalScopeTld = lastLabel === "localhost" || lastLabel === "local" || lastLabel === "lan"; // allow:hostname-compare-trailing-dot — see comment above; List-Id parts already split on `.` so trailing-dot label is empty and refused upstream
|
|
245
|
+
var isLocalScopeTld = lastLabel === "localhost" || lastLabel === "local" || lastLabel === "lan"; // allow:hostname-compare-trailing-dot-pre-split-refused — see comment above; List-Id parts already split on `.` so trailing-dot label is empty and refused upstream
|
|
246
246
|
if (caps.requireFqdn) {
|
|
247
247
|
if (parts.length < 3 && !isLocalScopeTld) { // FQDN requires ≥ 3 labels for non-local-scope namespace
|
|
248
248
|
return _refuse("list-id has < 3 labels for non-local-scope namespace (FQDN required under '" +
|
package/lib/log.js
CHANGED
|
@@ -589,7 +589,7 @@ function _escapeC0Controls(s) {
|
|
|
589
589
|
// runs before safeEnv on the boot path; safeEnv requires log, so log
|
|
590
590
|
// can't go through safeEnv to read its own level.
|
|
591
591
|
function _bootMinLevel() {
|
|
592
|
-
// allow:raw-process-env — see header comment above
|
|
592
|
+
// allow:raw-process-env-bootstrap — see header comment above
|
|
593
593
|
var raw = process.env.BLAMEJS_BOOT_LOG_LEVEL || process.env.LOG_LEVEL || "info";
|
|
594
594
|
return Object.prototype.hasOwnProperty.call(LEVELS, raw) ? LEVELS[raw] : LEVELS.info;
|
|
595
595
|
}
|
package/lib/mail-crypto-pgp.js
CHANGED
|
@@ -563,7 +563,7 @@ function sign(opts) {
|
|
|
563
563
|
// signed-part bytes plus the armored signature.
|
|
564
564
|
// MIME-boundary uniqueness only (not a security token); operator
|
|
565
565
|
// key/cert material flows through createSign/verify, not this path.
|
|
566
|
-
// allow:raw-randombytes-token — boundary string, not auth credential
|
|
566
|
+
// allow:raw-randombytes-token-mime-boundary — boundary string, not auth credential
|
|
567
567
|
var boundary = "blamejs-pgp-" + nodeCrypto.randomBytes(12).toString("hex");
|
|
568
568
|
// The OpenPGP signature covers the signed-part bytes exactly, so the
|
|
569
569
|
// multipart/signed wrapper is assembled as a Buffer — a JS-string round
|
|
@@ -72,7 +72,7 @@ function _scheme(req) {
|
|
|
72
72
|
// client used (forwarded), NOT a Secure/HSTS/origin trust decision. Routing
|
|
73
73
|
// through trustedProtocol would drop the forwarded scheme from spans behind a
|
|
74
74
|
// proxy (less accurate telemetry) for no security gain.
|
|
75
|
-
// allow:raw-xfp — telemetry label, not a trust sink (see above).
|
|
75
|
+
// allow:raw-xfp-telemetry-only — telemetry label, not a trust sink (see above).
|
|
76
76
|
var x = req.headers && (req.headers["x-forwarded-proto"] || "");
|
|
77
77
|
if (typeof x === "string" && x.length > 0) {
|
|
78
78
|
var first = x.split(",")[0].trim().toLowerCase();
|
|
@@ -82,7 +82,7 @@ function _scheme(req) {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
function _serverAddress(req) {
|
|
85
|
-
// allow:raw-xfp — display-only: server.address span attribute (telemetry),
|
|
85
|
+
// allow:raw-xfp-telemetry-only — display-only: server.address span attribute (telemetry),
|
|
86
86
|
// not an authority trust decision. Same rationale as _scheme above.
|
|
87
87
|
var hostHeader = req.headers && (req.headers["x-forwarded-host"] || req.headers.host);
|
|
88
88
|
if (typeof hostHeader === "string" && hostHeader.length > 0) {
|
package/lib/static.js
CHANGED
|
@@ -1409,7 +1409,7 @@ function create(opts) {
|
|
|
1409
1409
|
// pre-allocate a closure for every served byte. Tracked for extraction.
|
|
1410
1410
|
var idleTimer = null;
|
|
1411
1411
|
function resetIdleTimer() {
|
|
1412
|
-
if (idleTimer) clearTimeout(idleTimer); // allow:handrolled-debounce — file-stream idle deadline
|
|
1412
|
+
if (idleTimer) clearTimeout(idleTimer); // allow:handrolled-debounce-stream-idle — file-stream idle deadline
|
|
1413
1413
|
idleTimer = setTimeout(function () {
|
|
1414
1414
|
try { fileStream.destroy(_err("IDLE_TIMEOUT", "client idle for " + maxIdleMs + "ms")); }
|
|
1415
1415
|
catch (_) { /* stream already torn down */ }
|
|
@@ -1420,7 +1420,7 @@ function create(opts) {
|
|
|
1420
1420
|
|
|
1421
1421
|
// Cancellation propagation: when the client disconnects mid-stream.
|
|
1422
1422
|
function onClientClose() {
|
|
1423
|
-
try { fileStream.destroy(); } catch (_) { /* allow:silent-catch — stream already torn down */ }
|
|
1423
|
+
try { fileStream.destroy(); } catch (_) { /* allow:silent-catch-stream-teardown — stream already torn down */ }
|
|
1424
1424
|
releaseSlot();
|
|
1425
1425
|
if (idleTimer) { clearTimeout(idleTimer); idleTimer = null; }
|
|
1426
1426
|
}
|
|
@@ -1442,7 +1442,7 @@ function create(opts) {
|
|
|
1442
1442
|
error: e && e.message,
|
|
1443
1443
|
}, actorCtx));
|
|
1444
1444
|
}
|
|
1445
|
-
try { res.destroy(e); } catch (_) { /* allow:silent-catch — response already torn down */ }
|
|
1445
|
+
try { res.destroy(e); } catch (_) { /* allow:silent-catch-stream-teardown — response already torn down */ }
|
|
1446
1446
|
releaseSlot();
|
|
1447
1447
|
if (idleTimer) { clearTimeout(idleTimer); idleTimer = null; }
|
|
1448
1448
|
});
|
package/lib/vendor-data.js
CHANGED
|
@@ -113,7 +113,7 @@ function _timingSafeHexEqual(a, b) {
|
|
|
113
113
|
// length now guarantees equal byte length.
|
|
114
114
|
var ba = Buffer.from(a, "utf8");
|
|
115
115
|
var bb = Buffer.from(b, "utf8");
|
|
116
|
-
return nodeCrypto.timingSafeEqual(ba, bb); // allow:raw-timing-safe-equal — hex + length pre-check above guarantees same-length ASCII inputs; b.crypto wrapper would be circular at boot
|
|
116
|
+
return nodeCrypto.timingSafeEqual(ba, bb); // allow:raw-timing-safe-equal-boot-prechecked — hex + length pre-check above guarantees same-length ASCII inputs; b.crypto wrapper would be circular at boot
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
// KNOWN_VENDOR_DATA — the canonical list of vendored data names. Each
|
package/lib/watcher.js
CHANGED
|
@@ -528,7 +528,7 @@ function create(opts) {
|
|
|
528
528
|
throw new WatcherError("watcher/start-failed",
|
|
529
529
|
"watcher.create: initial poll walk failed: " + ((e && e.message) || String(e)));
|
|
530
530
|
}
|
|
531
|
-
pollTimer = setInterval(_pollTick, pollIntervalMs); // allow:timer-no-unref — .unref() called immediately below; timer doesn't pin the event loop
|
|
531
|
+
pollTimer = setInterval(_pollTick, pollIntervalMs); // allow:timer-no-unref-unrefed-below — .unref() called immediately below; timer doesn't pin the event loop
|
|
532
532
|
if (typeof pollTimer.unref === "function") pollTimer.unref();
|
|
533
533
|
} else {
|
|
534
534
|
try {
|
|
@@ -26,7 +26,6 @@ var safeSql = require("./safe-sql");
|
|
|
26
26
|
var safeUrl = require("./safe-url");
|
|
27
27
|
var safeJson = require("./safe-json");
|
|
28
28
|
var bCrypto = require("./crypto");
|
|
29
|
-
var httpClient = require("./http-client");
|
|
30
29
|
var frameworkSchema = require("./framework-schema");
|
|
31
30
|
var validateOpts = require("./validate-opts");
|
|
32
31
|
var lazyRequire = require("./lazy-require");
|
|
@@ -44,6 +43,11 @@ var vault = lazyRequire(function () { return require("./vault"); });
|
|
|
44
43
|
var ssrfGuard = lazyRequire(function () { return require("./ssrf-guard"); });
|
|
45
44
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
46
45
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
46
|
+
// Lazy — http-client pulls in node:http / node:https / node:http2; only the
|
|
47
|
+
// default delivery transport touches it. Keeping it lazy keeps b.webhook (which
|
|
48
|
+
// re-exports this module) free of the Node networking chain on its inbound
|
|
49
|
+
// verify path, so b.webhook.verify stays loadable in a Worker / edge runtime.
|
|
50
|
+
var httpClient = lazyRequire(function () { return require("./http-client"); });
|
|
47
51
|
|
|
48
52
|
var _err = WebhookDispatcherError.factory;
|
|
49
53
|
|
|
@@ -223,7 +227,7 @@ function dispatcher(opts) {
|
|
|
223
227
|
// Default transport: a real signed POST through the framework http client.
|
|
224
228
|
// Injectable so a test (or a non-HTTP transport) substitutes its own.
|
|
225
229
|
var httpRequest = opts.httpRequest || function (url, body, headers) {
|
|
226
|
-
return httpClient.request({
|
|
230
|
+
return httpClient().request({
|
|
227
231
|
method: "POST",
|
|
228
232
|
url: url,
|
|
229
233
|
headers: headers,
|
package/lib/webhook.js
CHANGED
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
var nodeCrypto = require("node:crypto");
|
|
51
51
|
var numericBounds = require("./numeric-bounds");
|
|
52
52
|
var bCrypto = require("./crypto");
|
|
53
|
-
var httpClient = require("./http-client");
|
|
54
53
|
var safeBuffer = require("./safe-buffer");
|
|
55
54
|
var safeUrl = require("./safe-url");
|
|
56
55
|
var retryHelper = require("./retry");
|
|
@@ -60,12 +59,20 @@ var numericChecks = require("./numeric-checks");
|
|
|
60
59
|
var requestHelpers = require("./request-helpers");
|
|
61
60
|
// Lazy — ssrf-guard pulls in the DNS/network stack; only touched on send().
|
|
62
61
|
var ssrfGuard = lazyRequire(function () { return require("./ssrf-guard"); });
|
|
62
|
+
// Lazy — http-client pulls in node:http / node:https / node:http2; only the
|
|
63
|
+
// outbound send() path touches it. Keeping it lazy lets b.webhook.verify (HMAC
|
|
64
|
+
// + timing-safe compare only) load in a Worker / edge runtime with no Node
|
|
65
|
+
// networking module available.
|
|
66
|
+
var httpClient = lazyRequire(function () { return require("./http-client"); });
|
|
63
67
|
var validateOpts = require("./validate-opts");
|
|
64
68
|
var { WebhookError } = require("./framework-error");
|
|
65
69
|
// b.webhook.dispatcher — durable signed-webhook delivery store. Lives in its
|
|
66
|
-
// own module (distinct domain: persistence) and
|
|
67
|
-
//
|
|
68
|
-
|
|
70
|
+
// own module (distinct domain: persistence) and pulls the SQL stack (and so
|
|
71
|
+
// node:fs). Lazy — only resolved when b.webhook.dispatcher is accessed — so
|
|
72
|
+
// importing the webhook module for the inbound verify path stays free of the
|
|
73
|
+
// persistence/networking stack and loads in a Worker / edge runtime. The
|
|
74
|
+
// module lazyRequires this file back, so the cycle stays deferred on both ends.
|
|
75
|
+
var webhookDispatcher = lazyRequire(function () { return require("./webhook-dispatcher"); });
|
|
69
76
|
|
|
70
77
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
71
78
|
|
|
@@ -472,7 +479,7 @@ function signer(opts) {
|
|
|
472
479
|
} catch (_e) { hostLabel = ""; }
|
|
473
480
|
try {
|
|
474
481
|
var res = await retryHelper.withRetry(function () {
|
|
475
|
-
return httpClient.request(requestOpts);
|
|
482
|
+
return httpClient().request(requestOpts);
|
|
476
483
|
}, retryOpts);
|
|
477
484
|
var statusCode = (res && (res.statusCode || res.status)) || 0;
|
|
478
485
|
_emitEvent("webhook.send", 1, {
|
|
@@ -1011,7 +1018,14 @@ module.exports = {
|
|
|
1011
1018
|
// v0.11.25 — Stripe-shaped inbound HMAC-SHA-256 verifier + signer.
|
|
1012
1019
|
verify: verify,
|
|
1013
1020
|
sign: sign,
|
|
1014
|
-
// Durable signed-webhook delivery store (sign + persist + deliver + retry +
|
|
1015
|
-
// dead-letter + operator replay). Defined in lib/webhook-dispatcher.js.
|
|
1016
|
-
dispatcher: webhookDispatcher.dispatcher,
|
|
1017
1021
|
};
|
|
1022
|
+
|
|
1023
|
+
// Durable signed-webhook delivery store (sign + persist + deliver + retry +
|
|
1024
|
+
// dead-letter + operator replay). Defined in lib/webhook-dispatcher.js, which
|
|
1025
|
+
// pulls the SQL/persistence stack — exposed as a lazy getter so requiring the
|
|
1026
|
+
// webhook module for the inbound verify path doesn't load it (edge-safe).
|
|
1027
|
+
Object.defineProperty(module.exports, "dispatcher", {
|
|
1028
|
+
enumerable: true,
|
|
1029
|
+
configurable: true,
|
|
1030
|
+
get: function () { return webhookDispatcher().dispatcher; },
|
|
1031
|
+
});
|
package/package.json
CHANGED
package/sbom.cdx.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:4097a213-458e-41ee-81c8-2db35819839f",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-06-
|
|
8
|
+
"timestamp": "2026-06-26T19:40:07.451Z",
|
|
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.15.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.15.31",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.15.
|
|
25
|
+
"version": "0.15.31",
|
|
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.15.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.15.31",
|
|
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.15.
|
|
57
|
+
"ref": "@blamejs/core@0.15.31",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|