@blamejs/core 0.6.68 → 0.6.70

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,10 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.6.x
10
10
 
11
+ - **0.6.70** (2026-05-03) — `lib/numeric-bounds` extended to 3 more sites the v0.6.69 sweep didn't cover. **`lib/middleware/csp-nonce.js` `nonceBytes`** — pre-fix the `typeof === "number"` check accepted `Infinity` / `NaN` (both bypass `< MIN_NONCE_BYTES` because every comparison-with-NaN-or-Infinity is false), then crashed per-request inside `crypto.generateBytes(Infinity)` with `ERR_OUT_OF_RANGE`. The DoS-shape: an operator typo at boot took down every CSP-protected route at request time. Now rejects at create() with `csp-nonce/bad-nonce-bytes`. **`lib/migrations.js` and `lib/external-db-migrate.js` `staleAfterMs`** — both used the `> 0` guard which silently accepted `Infinity`. `(Date.now() - lockedAt) > Infinity` is always false → `staleAfterMs: Infinity` was identical to the `0` default ("never replace") but obscured the typo. Operators wanting "never expire" now pass `0` explicitly; everything else (Infinity / NaN / fractional / negative / non-number) rejects with a clear message. **Tests** — 6 new layer-0 assertions extending `test/layer-0-primitives/numeric-bounds.test.js` (3 csp-nonce reject paths + 3 migration locks — already covered indirectly via existing test/integration suite). Smoke 7293 → 7296 / wiki e2e 178 / Linux 85.9s / eslint clean / shellcheck clean.
12
+
13
+ - **0.6.69** (2026-05-03) — `lib/numeric-bounds.js` shared validator applied across every numeric-opt site that previously accepted `Infinity` / `NaN` and silently bypassed its OOM / size / depth cap. Pre-fix the recurring pattern `typeof opts.X === "number" && opts.X > 0` was vulnerable everywhere it shipped: `Infinity > Infinity` is false, `byteLength > NaN` is false, `Number.isFinite()` was missing. Operators with env-var coercions (`Number(process.env.MAX_X || "")` produces `NaN` for missing values, `Infinity` for typo'd ones) silently lost their cap. **The unified fix:** new `lib/numeric-bounds.js` exposes `isPositiveFiniteInt(value)` + `shape(value)` (the latter formats `"number Infinity"` / `"number NaN"` / `"string \"100\""` so the actual coercion is visible — `JSON.stringify` collapses Infinity/NaN to `"null"` and hides the typo). Each call site uses its own framework-error class (constructors split between `(message, code)` and `(code, message)` conventions across the codebase) but routes through the shared predicate. **Sites swept:** `lib/safe-buffer.js` (`boundedChunkCollector`, `toBuffer`, `normalizeText` — the v0.6.57 fix only covered the first), `lib/atomic-file.js` (refactored from v0.6.68's inline check), `lib/csv.js` (parse `maxBytes` was operator-overridable to Infinity → multi-megabyte CSV bodies through unbounded), `lib/safe-url.js` (`maxUrlLength` opt was the v0.6.62 fix's escape hatch — now also bounded), `lib/mail-bounce.js` (`maxBytes` for inbound webhook body — DoS-shape on bounce intake). **Tests** — new `test/layer-0-primitives/numeric-bounds.test.js` with 35 assertions (12 helper + 9 reject-Infinity at each consumer + 7 accept-legit smoke calls + 7 helper-shape format). Smoke 7258 → 7293 / wiki e2e 178 / Linux 86.0s / eslint clean / shellcheck clean.
14
+
11
15
  - **0.6.68** (2026-05-03) — `b.atomicFile.read` / `readSync` enforce strict `maxBytes` validation. Same bug class as v0.6.57's `safeBuffer.boundedChunkCollector` fix: pre-fix the size check was `if (stat.size > opts.maxBytes)`, which silently accepted `Infinity` (`stat.size > Infinity` always false → reads any file regardless of size, defeating the OOM cap). Operators with `Number(env.MAX_READ_BYTES || "")` coercion bugs got `NaN` on missing values and unbounded reads on Infinity-typo'd values. New `_validateMaxBytes` runs before the size check and rejects `Infinity` / `NaN` / non-integer / negative / zero / non-number with `atomic-file/bad-opt`. Real-world consumers (vault.initPlaintext, audit-sign, db.loadOrCreateDbKey, etc.) all pass real positive integers via `C.BYTES.*` helpers and are unaffected. **Tests** — 7 new layer-0 boot-validation assertions in `test/00-primitives.js` (Infinity, NaN, 0, -1, 3.5, "100", null all reject). Smoke 7251 → 7258 / wiki e2e 178 / Linux 86.0s / eslint clean / shellcheck clean.
12
16
 
13
17
  - **0.6.67** (2026-05-03) — canonical-JSON walker extracted to `lib/canonical-json.js` and applied to `lib/audit-tools.js` + `lib/config-drift.js`. Same bug class as v0.6.60 (pagination) and v0.6.66 (audit-chain) lived in two more sites: `audit-tools._canonicalize` (used for backup-bundle JSONL serialisation, requires byte-equivalence with audit-chain) and `config-drift._stableStringify` (used to hash framework config for post-boot tamper detection). Both still had the silent-data-loss walk — Date → `{}`, Buffer → `{"0":97,…}`, Map / Set → `{}`, BigInt throws, circular references stack-overflow. New `lib/canonical-json.js` exposes `stringify(value, opts?)` with `opts.bufferAs = "hex" | "reject"` (default `"hex"` for crypto / config / audit; `"reject"` for pagination's strict-cursor policy). All four call sites — audit-chain, audit-tools, config-drift, pagination — now route through it; the four near-identical inline walkers collapse to one. **Stored-row + bundle compatibility** preserved: existing audit rows verify identically (their `metadata` columns are JSON strings); backup bundles produced pre-v0.6.67 round-trip correctly because byte output for plain types is unchanged. **Tests** — 17 layer-0 audit-chain assertions from v0.6.66 cover the unified walker; existing pagination tests cover `bufferAs: "reject"`. Smoke 7251 / wiki e2e 178 / Linux 86.3s / eslint clean / shellcheck clean.
@@ -37,6 +37,7 @@ var { generateToken, sha3Hash } = require("./crypto");
37
37
  var safeJson = require("./safe-json");
38
38
  var C = require("./constants");
39
39
  var safeBuffer = require("./safe-buffer");
40
+ var numericBounds = require("./numeric-bounds");
40
41
  var safeAsync = require("./safe-async");
41
42
  var retry = require("./retry");
42
43
  var { FrameworkError } = require("./framework-error");
@@ -331,17 +332,13 @@ function readSync(filepath, opts) {
331
332
  return _readSyncCore(filepath, opts);
332
333
  }
333
334
 
334
- // maxBytes must be a positive finite integer. Pre-validation catches the
335
- // `Infinity` typo / coercion case where an operator's
336
- // `Number(env.MAX_READ_BYTES || "")` produced Infinity, which would
337
- // otherwise make `stat.size > Infinity` always false and read any file
338
- // regardless of size — defeating the OOM cap entirely. Same bug class
339
- // as v0.6.57's safeBuffer.boundedChunkCollector fix.
335
+ // maxBytes via shared lib/numeric-bounds Infinity / NaN bypass the
336
+ // stat.size cap (any-comparison-with-Infinity-or-NaN is false).
340
337
  function _validateMaxBytes(maxBytes) {
341
- if (typeof maxBytes !== "number" || !Number.isFinite(maxBytes) ||
342
- !Number.isInteger(maxBytes) || maxBytes <= 0) {
338
+ if (!numericBounds.isPositiveFiniteInt(maxBytes)) {
343
339
  throw new AtomicFileError(
344
- "maxBytes must be a positive finite integer; got " + JSON.stringify(maxBytes),
340
+ "atomicFile.read: maxBytes must be a positive finite integer; got " +
341
+ numericBounds.shape(maxBytes),
345
342
  "atomic-file/bad-opt");
346
343
  }
347
344
  }
package/lib/csv.js CHANGED
@@ -42,6 +42,7 @@
42
42
  * Throws CsvError (FrameworkError, permanent) on shape violations.
43
43
  */
44
44
  var C = require("./constants");
45
+ var numericBounds = require("./numeric-bounds");
45
46
  var { defineClass } = require("./framework-error");
46
47
 
47
48
  var CsvError = defineClass("CsvError", { alwaysPermanent: true });
@@ -83,6 +84,13 @@ function _validateDelim(name, value) {
83
84
 
84
85
  function parse(input, opts) {
85
86
  opts = Object.assign({}, DEFAULTS_PARSE, opts || {});
87
+ // maxBytes via shared lib/numeric-bounds — Infinity / NaN bypass the
88
+ // body cap and let a hostile multi-megabyte CSV through unbounded.
89
+ if (!numericBounds.isPositiveFiniteInt(opts.maxBytes)) {
90
+ throw new CsvError("csv/bad-opt",
91
+ "csv.parse: maxBytes must be a positive finite integer; got " +
92
+ numericBounds.shape(opts.maxBytes));
93
+ }
86
94
 
87
95
  var s;
88
96
  if (typeof input === "string") s = input;
@@ -51,6 +51,7 @@
51
51
  var path = require("path");
52
52
  var atomicFile = require("./atomic-file");
53
53
  var lazyRequire = require("./lazy-require");
54
+ var numericBounds = require("./numeric-bounds");
54
55
  var validateOpts = require("./validate-opts");
55
56
  var { defineClass } = require("./framework-error");
56
57
 
@@ -113,8 +114,17 @@ async function _acquireLock(xdb, opts) {
113
114
  await _ensureLockTable(xdb);
114
115
  var holder = _lockHolderId();
115
116
  var nowMs = Date.now();
116
- var staleAfterMs = (opts && typeof opts.staleAfterMs === "number" && opts.staleAfterMs > 0)
117
- ? opts.staleAfterMs : 0;
117
+ // See migrations.acquireLock for the same fix Infinity was
118
+ // silently identical to 0 (no staleness check) but obscured the typo.
119
+ var staleAfterMs;
120
+ if (!opts || opts.staleAfterMs === undefined) {
121
+ staleAfterMs = 0;
122
+ } else if (!numericBounds.isNonNegativeFiniteInt(opts.staleAfterMs)) {
123
+ throw new Error("externalDb.migrate.acquireLock: staleAfterMs must " +
124
+ "be a non-negative finite integer; got " + numericBounds.shape(opts.staleAfterMs));
125
+ } else {
126
+ staleAfterMs = opts.staleAfterMs;
127
+ }
118
128
  try {
119
129
  await xdb.query(
120
130
  "INSERT INTO " + Q_LOCK + " (scope, lockedAt, lockedBy) VALUES ('lock', $1, $2)",
@@ -64,6 +64,7 @@
64
64
  */
65
65
 
66
66
  var lazyRequire = require("./lazy-require");
67
+ var numericBounds = require("./numeric-bounds");
67
68
  var audit = lazyRequire(function () { return require("./audit"); });
68
69
  var safeJson = require("./safe-json");
69
70
  var C = require("./constants");
@@ -400,7 +401,20 @@ function handler(opts) {
400
401
  var verify = typeof opts.verify === "function" ? opts.verify : null;
401
402
  var onBounce = typeof opts.onBounce === "function" ? opts.onBounce : null;
402
403
  var auditOn = opts.audit !== false;
403
- var maxBytes = typeof opts.maxBytes === "number" ? opts.maxBytes : MAX_BODY_BYTES;
404
+ // maxBytes must be a positive finite integer (Infinity / NaN /
405
+ // negative / non-integer all bypass the body cap). See
406
+ // lib/numeric-bounds for the rationale shared with every other
407
+ // numeric-opt site swept in v0.6.69.
408
+ var maxBytes;
409
+ if (opts.maxBytes === undefined) {
410
+ maxBytes = MAX_BODY_BYTES;
411
+ } else if (!numericBounds.isPositiveFiniteInt(opts.maxBytes)) {
412
+ throw new MailBounceError("mail-bounce/bad-opt",
413
+ "mailBounce.handler: opts.maxBytes must be a positive finite " +
414
+ "integer; got " + numericBounds.shape(opts.maxBytes), true);
415
+ } else {
416
+ maxBytes = opts.maxBytes;
417
+ }
404
418
 
405
419
  function _emit(event) {
406
420
  if (!auditOn) return;
@@ -113,6 +113,7 @@
113
113
  */
114
114
 
115
115
  var crypto = require("../crypto");
116
+ var numericBounds = require("../numeric-bounds");
116
117
  var validateOpts = require("../validate-opts");
117
118
  var { defineClass } = require("../framework-error");
118
119
 
@@ -237,7 +238,18 @@ function create(opts) {
237
238
  }
238
239
  directives[i] = directives[i].toLowerCase();
239
240
  }
240
- var nonceBytes = typeof opts.nonceBytes === "number" ? opts.nonceBytes : DEFAULT_NONCE_BYTES;
241
+ var nonceBytes = opts.nonceBytes !== undefined ? opts.nonceBytes : DEFAULT_NONCE_BYTES;
242
+ // Pre-fix the typeof-only check accepted Infinity / NaN — both
243
+ // bypassed the `< MIN_NONCE_BYTES` guard (NaN < N is always false,
244
+ // Infinity < N is always false), then crashed per-request when
245
+ // `crypto.generateBytes(Infinity)` hit ERR_OUT_OF_RANGE. Route through
246
+ // shared numeric-bounds (positive finite int) before the lower-bound
247
+ // check so the typo / coercion is caught at create() time.
248
+ if (!numericBounds.isPositiveFiniteInt(nonceBytes)) {
249
+ throw new CspNonceError("csp-nonce/bad-nonce-bytes",
250
+ "nonceBytes must be a positive finite integer; got " +
251
+ numericBounds.shape(nonceBytes));
252
+ }
241
253
  if (nonceBytes < MIN_NONCE_BYTES) {
242
254
  throw new CspNonceError("csp-nonce/bad-nonce-bytes",
243
255
  "nonceBytes must be >= " + MIN_NONCE_BYTES + " (got " + nonceBytes + "). " +
package/lib/migrations.js CHANGED
@@ -41,6 +41,7 @@
41
41
  var path = require("path");
42
42
  var atomicFile = require("./atomic-file");
43
43
  var lazyRequire = require("./lazy-require");
44
+ var numericBounds = require("./numeric-bounds");
44
45
  var dbModule = lazyRequire(function () { return require("./db"); });
45
46
  var validateOpts = require("./validate-opts");
46
47
  var { FrameworkError } = require("./framework-error");
@@ -108,8 +109,21 @@ function _acquireLock(db, opts) {
108
109
  _ensureLockTable(db);
109
110
  var holder = _lockHolderId();
110
111
  var nowMs = Date.now();
111
- var staleAfterMs = (opts && typeof opts.staleAfterMs === "number" && opts.staleAfterMs > 0)
112
- ? opts.staleAfterMs : 0;
112
+ // staleAfterMs gates whether an existing lock is considered stale.
113
+ // 0 (the default) means "never replace — wait for the operator".
114
+ // Pre-fix Infinity was accepted but degenerate `(now - lockedAt) >
115
+ // Infinity` to always-false, identical to 0 but with an obscured
116
+ // typo. Reject Infinity / NaN / non-integer / negative — operators
117
+ // wanting "never" pass 0 explicitly.
118
+ var staleAfterMs;
119
+ if (!opts || opts.staleAfterMs === undefined) {
120
+ staleAfterMs = 0;
121
+ } else if (!numericBounds.isNonNegativeFiniteInt(opts.staleAfterMs)) {
122
+ throw new Error("migrations.acquireLock: staleAfterMs must be a " +
123
+ "non-negative finite integer; got " + numericBounds.shape(opts.staleAfterMs));
124
+ } else {
125
+ staleAfterMs = opts.staleAfterMs;
126
+ }
113
127
  // Try to insert; if there's a stale lock, optionally force-replace it.
114
128
  try {
115
129
  db.prepare(
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ /**
3
+ * numeric-bounds — shared validators for operator-tunable numeric opts.
4
+ *
5
+ * Replaces the recurring `typeof opts.X === "number" && opts.X > 0`
6
+ * pattern that ships across the framework. Pre-v0.6.69 each site had
7
+ * its own slightly-different inline check; the bug they all shared was
8
+ * accepting `Infinity` (silently bypassing OOM caps, body size limits,
9
+ * URL caps, depth limits) and `NaN` (also bypassing because every
10
+ * comparison with NaN is false). v0.6.57 fixed boundedChunkCollector,
11
+ * v0.6.68 fixed atomicFile, v0.6.69 sweeps the rest.
12
+ *
13
+ * var nb = require("./numeric-bounds");
14
+ *
15
+ * if (!nb.isPositiveFiniteInt(opts.maxBytes)) {
16
+ * throw new CsvError("csv/bad-opt",
17
+ * "csv.parse: maxBytes must be a positive finite integer; got " +
18
+ * nb.shape(opts.maxBytes));
19
+ * }
20
+ *
21
+ * The helper returns a predicate + a shape-formatter rather than
22
+ * throwing itself, because the framework's error classes use two
23
+ * different constructor conventions:
24
+ *
25
+ * AtomicFileError, SafeBufferError, SafeUrlError (message, code)
26
+ * defineClass(...)-built (CsvError, MailBounceError…) (code, message, permanent[, statusCode])
27
+ *
28
+ * Each call site throws its own class, with whatever ctor shape that
29
+ * class wants. The helper just owns the validation rule + the consistent
30
+ * shape format ("number Infinity" / "number NaN" / "string \"100\"") so
31
+ * the typo / coercion is visible in the error message — `JSON.stringify`
32
+ * collapses Infinity / NaN to "null" which obscures what went wrong.
33
+ */
34
+
35
+ // Shape formatter — typeof + String preserves "number Infinity" /
36
+ // "number NaN" / "string foo". Strings get JSON-quoted so trailing
37
+ // whitespace / control chars are visible.
38
+ function shape(value) {
39
+ if (typeof value === "string") {
40
+ return "string " + JSON.stringify(value);
41
+ }
42
+ return (typeof value) + " " + String(value);
43
+ }
44
+
45
+ function isPositiveFiniteInt(value) {
46
+ return typeof value === "number" && Number.isFinite(value) &&
47
+ Number.isInteger(value) && value > 0;
48
+ }
49
+
50
+ function isNonNegativeFiniteInt(value) {
51
+ return typeof value === "number" && Number.isFinite(value) &&
52
+ Number.isInteger(value) && value >= 0;
53
+ }
54
+
55
+ module.exports = {
56
+ shape: shape,
57
+ isPositiveFiniteInt: isPositiveFiniteInt,
58
+ isNonNegativeFiniteInt: isNonNegativeFiniteInt,
59
+ };
@@ -37,6 +37,7 @@
37
37
  * if the caller doesn't pass one.
38
38
  */
39
39
 
40
+ var numericBounds = require("./numeric-bounds");
40
41
  var { FrameworkError } = require("./framework-error");
41
42
 
42
43
  class SafeBufferError extends FrameworkError {
@@ -57,7 +58,18 @@ function _throw(errorClass, message, code) {
57
58
 
58
59
  function normalizeText(input, opts) {
59
60
  opts = opts || {};
60
- var maxBytes = (typeof opts.maxBytes === "number" && opts.maxBytes > 0) ? opts.maxBytes : null;
61
+ // maxBytes optional; positive finite int when set Infinity / NaN
62
+ // bypass the cap.
63
+ var maxBytes = null;
64
+ if (opts.maxBytes !== undefined && opts.maxBytes !== null) {
65
+ if (!numericBounds.isPositiveFiniteInt(opts.maxBytes)) {
66
+ throw new SafeBufferError(
67
+ "normalizeText: maxBytes must be a positive finite integer; got " +
68
+ numericBounds.shape(opts.maxBytes),
69
+ "buffer/bad-arg");
70
+ }
71
+ maxBytes = opts.maxBytes;
72
+ }
61
73
  var stripBom = opts.stripBom !== false; // default true
62
74
  var errClass = opts.errorClass;
63
75
  var typeCode = opts.typeCode || "buffer/wrong-input-type";
@@ -83,7 +95,17 @@ function normalizeText(input, opts) {
83
95
 
84
96
  function toBuffer(data, opts) {
85
97
  opts = opts || {};
86
- var maxBytes = (typeof opts.maxBytes === "number" && opts.maxBytes > 0) ? opts.maxBytes : null;
98
+ // maxBytes optional; positive finite int when provided.
99
+ var maxBytes = null;
100
+ if (opts.maxBytes !== undefined && opts.maxBytes !== null) {
101
+ if (!numericBounds.isPositiveFiniteInt(opts.maxBytes)) {
102
+ throw new SafeBufferError(
103
+ "toBuffer: maxBytes must be a positive finite integer; got " +
104
+ numericBounds.shape(opts.maxBytes),
105
+ "buffer/bad-arg");
106
+ }
107
+ maxBytes = opts.maxBytes;
108
+ }
87
109
  var errClass = opts.errorClass;
88
110
  var typeCode = opts.typeCode || "buffer/wrong-input-type";
89
111
  var sizeCode = opts.sizeCode || "buffer/too-large";
@@ -112,23 +134,16 @@ function toBuffer(data, opts) {
112
134
 
113
135
  function boundedChunkCollector(opts) {
114
136
  opts = opts || {};
115
- // maxBytes must be a positive finite integer. Accepting `Infinity`
116
- // would defeat the entire point of the bounded collector (a hostile
117
- // 10-GB upstream would accumulate fully); accepting `3.5` would set
118
- // a non-sensical fractional cap that confuses downstream `total +
119
- // chunk.length > maxBytes` arithmetic. NaN, negative, zero, non-
120
- // numbers all reject with the same `buffer/bad-arg` so operators
121
- // see one consistent error at boot from a typo or misconfiguration.
122
- var maxBytes = (typeof opts.maxBytes === "number" &&
123
- Number.isFinite(opts.maxBytes) &&
124
- Number.isInteger(opts.maxBytes) &&
125
- opts.maxBytes > 0) ? opts.maxBytes : null;
126
- if (maxBytes === null) {
137
+ // maxBytes required, positive finite integer. Accepting Infinity
138
+ // defeats the entire point of the bounded collector (a hostile 10-GB
139
+ // upstream would accumulate fully).
140
+ if (!numericBounds.isPositiveFiniteInt(opts.maxBytes)) {
127
141
  throw new SafeBufferError(
128
142
  "boundedChunkCollector requires maxBytes (positive finite integer); got " +
129
- JSON.stringify(opts.maxBytes),
143
+ numericBounds.shape(opts.maxBytes),
130
144
  "buffer/bad-arg");
131
145
  }
146
+ var maxBytes = opts.maxBytes;
132
147
  var errClass = opts.errorClass;
133
148
  var sizeCode = opts.sizeCode || "buffer/too-large";
134
149
  var sizeMsg = opts.sizeMessage || "stream body exceeds maxBytes";
package/lib/safe-url.js CHANGED
@@ -48,6 +48,7 @@
48
48
  * trying and failing weirdly later.
49
49
  */
50
50
 
51
+ var numericBounds = require("./numeric-bounds");
51
52
  var { FrameworkError } = require("./framework-error");
52
53
  var { URL } = require("url");
53
54
 
@@ -87,9 +88,18 @@ function parse(url, opts) {
87
88
  ? opts.allowedProtocols
88
89
  : ALLOW_HTTP_TLS;
89
90
  var errClass = opts.errorClass;
90
- var maxUrlLength = (typeof opts.maxUrlLength === "number" && opts.maxUrlLength > 0)
91
- ? opts.maxUrlLength
92
- : DEFAULT_MAX_URL_LENGTH;
91
+ // maxUrlLength via shared lib/numeric-bounds Infinity / NaN would
92
+ // silently bypass the cap (size > Infinity is always false).
93
+ var maxUrlLength;
94
+ if (opts.maxUrlLength === undefined) {
95
+ maxUrlLength = DEFAULT_MAX_URL_LENGTH;
96
+ } else if (!numericBounds.isPositiveFiniteInt(opts.maxUrlLength)) {
97
+ throw _makeError(errClass, "safe-url/bad-opt",
98
+ "safeUrl.parse: maxUrlLength must be a positive finite integer; got " +
99
+ numericBounds.shape(opts.maxUrlLength));
100
+ } else {
101
+ maxUrlLength = opts.maxUrlLength;
102
+ }
93
103
 
94
104
  if (url == null || url === "") {
95
105
  throw _makeError(errClass, "safe-url/missing", "url is required");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.6.68",
3
+ "version": "0.6.70",
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:3d7e40d6-b790-48ba-ab7c-c25a893da190",
5
+ "serialNumber": "urn:uuid:82655a7f-a10b-4642-942a-226f5b1f76bb",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-03T15:00:01.675Z",
8
+ "timestamp": "2026-05-03T15:29:33.757Z",
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.6.68",
22
+ "bom-ref": "@blamejs/core@0.6.70",
23
23
  "type": "library",
24
24
  "name": "blamejs",
25
- "version": "0.6.68",
25
+ "version": "0.6.70",
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.6.68",
29
+ "purl": "pkg:npm/%40blamejs/core@0.6.70",
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.6.68",
57
+ "ref": "@blamejs/core@0.6.70",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]