@blamejs/core 0.13.9 → 0.13.11

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.13.x
10
10
 
11
+ - v0.13.11 (2026-05-27) — **Test-suite reliability: replaced fixed-delay waits in the rate-limiter and scheduler suites with condition polling.** No runtime behaviour changes. The rate-limiter, scheduler, and websocket-channel test suites waited for asynchronous work to settle by draining a fixed number of event-loop ticks before asserting. Under heavily parallel CI that budget was occasionally too short, so an assertion read state before the async work (a cluster-backend counter update, a scheduler tick-claim) had landed — an intermittent failure unrelated to the code under test. Those waits now poll the observable condition (helpers.waitUntil) and exit as soon as it holds, with a generous upper bound, so they pass quickly on fast machines and reliably under load. A build gate is added so the fixed-tick-drain shape cannot be reintroduced. **Fixed:** *Flaky fixed-budget waits in the rate-limiter / scheduler / sandbox test suites made contention-tolerant* — The rate-limit-cluster and scheduler-exactly-once suites drained a fixed count of event-loop ticks before asserting on asynchronously-updated state; under contended CI the budget could expire before the work settled, producing intermittent failures. They now wait on the actual observable condition (a written response, a settled counter). The sandbox suite's success-path cases gave the worker a 5 s execution budget that cold worker-thread startup under heavily parallel Windows CI could just exceed; those are raised to the framework's 10 s ceiling. Affects test code only — no change to shipped framework behaviour. The unused tick-drain helper in the websocket-channel suite was removed. **Detectors:** *Build gate rejects the fixed-tick-drain wait shape in tests* — A new test-suite lint rule flags the counted microtask/tick-drain idiom (reassigning a promise to its own `.then()` in a loop to wait a fixed number of ticks), the sibling of the existing fixed-`setTimeout`-sleep rule. A single event-loop yield is unaffected; only the drain-as-wait shape is rejected, directing the wait to condition polling instead.
12
+
13
+ - v0.13.10 (2026-05-27) — **Documented-but-inert options wired up, a non-existent CVE reference removed, and a silent iCalendar cap-bypass fixed.** A sweep for places where a documented option or citation did not match what the code does. The most operator-relevant fix: b.calendar.fromIcal documented a safeIcalOpts option that forwards parser caps (byte size, RRULE limits, nesting depth) to b.safeIcal.parse, but the value was never forwarded — so an operator who set tight caps through it got the default profile instead, silently. That is corrected; the nested options now reach the parser. b.archive.read.zip documented an AbortSignal option that was never honored; it now aborts the read at the entry boundary. b.auth.fal documented a bearerOnly alias that had no effect; it now forces the no-proof-of-possession path and refuses the contradictory combination of bearerOnly:true with a holder-of-key binding. Separately, the auth verification paths cited CVE-2026-23993 (13 places) for the "reject an unknown alg before key lookup" guard — that CVE id does not exist (the registry has no record of it); the citation is replaced with the weakness class (CWE-347 / CWE-757) and the real, verifiable neighboring CVEs. The circuit-breaker error-code note that promised a rename "in v0.10" is corrected to the actual plan (v1.0), and the build gate that catches overdue version promises now also catches two-part version numbers. **Changed:** *`b.auth.fal` `bearerOnly` is now a real alias and refuses contradictions* — `bearerOnly: true` now forces the no-proof-of-possession path (equivalent to `hokBinding: null`), as documented. Passing `bearerOnly: true` together with a non-null `hokBinding` is a contradictory assurance request and is now refused at the call rather than silently resolved one way. **Fixed:** *`b.calendar.fromIcal` now forwards `safeIcalOpts` to the parser* — The documented `safeIcalOpts` option (parser caps: max bytes, RRULE COUNT/BYxxx limits, nesting depth) was not being passed to `b.safeIcal.parse` — when supplied under the documented nested key it was silently ignored and the parser ran with its default profile. Both forms now reach the parser: the documented nested `{ safeIcalOpts: { ... } }` and the top-level `{ profile, ... }` that earlier releases accepted, with the nested form winning on conflict. No caller regresses. · *`b.archive.read.zip` honors the documented `signal` (AbortSignal)* — The `signal` option was documented but never read. A large or slow archive read can now be aborted cooperatively — the reader checks the signal at each entry boundary (`inspect`, `entries`, `extractEntries`, `extract`) and rejects with an `archive-read/aborted` error. · *Removed a non-existent CVE reference from the JWT/JWE verification paths* — The "reject an unknown/unsupported `alg` before any key lookup" guard in `b.auth.jwt.verifyExternal`, `b.auth.oauth.verifyIdToken`, `b.auth.oid4vci`, and `b.auth.sd-jwt-vc` cited a CVE id that the registry has no record of. The behaviour is unchanged; the citation is now the weakness class it defends (CWE-347 improper signature verification / CWE-757 algorithm downgrade) alongside the real, verifiable alg-confusion / JWE-bypass CVEs already cited beside it. **Detectors:** *Overdue-version-promise gate now catches two-part version numbers* — The build gate that flags a deferral whose promised landing version has already shipped previously matched only three-part versions (`vN.N.N`); a two-part promise (`vN.N`) slipped past it. It now matches both. The `b.circuitBreaker` `CIRCUIT_OPEN` error-code note that pointed at a passed version is corrected to its actual plan (rename at v1.0, with a deprecation warning a minor ahead).
14
+
11
15
  - v0.13.9 (2026-05-26) — **Corrected CVE citations in source threat annotations + a build gate that refuses malformed CVE identifiers.** Several source-comment threat annotations cited CVE identifiers that were rejected by the numbering authority (never assigned to a real issue), attributed to the wrong product, or structurally malformed (a placeholder with a non-numeric sequence). The annotated defenses are unchanged — every cap, refusal, and constant-time comparison behaves exactly as before; only the reference labels were corrected, each to a verifiable CVE or to the underlying weakness class (CWE / RFC) where no single CVE fits. Notable corrections: the S/MIME SHA-1 / MD5 certificate-signature refusal now cites the SHAttered collision and RFC 8551 §2.5 instead of a rejected candidate id; decompression-output caps cite CWE-409 and CVE-2025-0725 instead of a fabricated placeholder; the iCalendar RRULE / nesting / byte caps describe the calendar-bomb recursion-DoS class instead of an unrelated SSRF advisory; and the SAML signature-wrapping (XSW) defense now cites the actively-exploited CVE-2024-45409 (ruby-saml, CVSS 10.0) and CVE-2025-25291 / -25292 that the duplicate-element refusal defeats. A new build-time detector refuses any CVE token whose sequence number is not all-numeric, so a placeholder identifier can never reach a release again. **Fixed:** *Corrected rejected / misattributed / malformed CVE references in source threat annotations* — Threat-annotation comments across the mail, crypto, auth, guard, and safe modules carried CVE identifiers that were rejected by the CVE numbering authority, attributed to the wrong product, or written as non-numeric placeholders. Each was corrected to a verifiable CVE or to the weakness class (CWE / RFC) it defends. No runtime behaviour changed — the defenses these comments describe are unchanged. The S/MIME certificate check's SHA-1 / MD5 refusal message now names the SHAttered collision and RFC 8551 §2.5; the SAML XSW defense now names CVE-2024-45409 and CVE-2025-25291 / -25292. **Detectors:** *`malformed-cve-identifier` — refuses structurally-invalid CVE tokens at build time* — A CVE identifier's sequence number is always numeric (`CVE-<year>-<digits>`). The new detector refuses any CVE token whose post-year segment contains a letter — the placeholder shape that lets a fabricated reference slip past review. It cannot verify that a well-formed id is real or correctly attributed (that stays a review responsibility), but it makes the structurally-invalid class impossible to ship.
12
16
 
13
17
  - v0.13.8 (2026-05-26) — **In-memory archive extraction for read-only / serverless filesystems.** Archive readers gain an in-memory extraction path so an uploaded archive can be opened and its contents read without writing anything to disk — the case a read-only or ephemeral serverless filesystem requires. b.archive.read.zip(...).extractEntries() and b.archive.read.tar(...).extractEntries() are async generators that yield each regular file entry as { name, bytes, size }, applying the same bomb-policy caps, b.guardArchive metadata cascade (which refuses a Zip-Slip / traversal archive wholesale), and entry-type-policy refusals as the disk extract() — only the disk realpath agreement check is omitted, since nothing is written and the caller owns where the returned bytes land. Directory and link entries carry no content and are not yielded. The guard cascade is factored into one shared path so disk and in-memory extraction refuse identically. Also a documentation fix: b.archive.gz no longer claims a b.archive.zip().toGzip() convenience exists — a ZIP is already DEFLATE-compressed per entry, so gzip-wrapping it gains nothing; gzip the uncompressed tar stream (the canonical .tar.gz) instead. **Added:** *`extractEntries()` — in-memory archive extraction (ZIP + tar)* — `b.archive.read.zip(source).extractEntries(opts?)` and `b.archive.read.tar(source).extractEntries(opts?)` are async generators yielding `{ name, bytes, size }` per regular file entry, never touching disk — for serverless / read-only filesystems where the disk `extract({ destination })` path cannot run. Same bomb-policy, guard-archive cascade, and entry-type-policy refusals as disk extraction; the bytes are byte-identical to what `extract()` writes. **Fixed:** *Removed the inaccurate `b.archive.zip().toGzip()` doc claim* — The `b.archive.gz` documentation described a `b.archive.zip().toGzip()` convenience method that does not (and should not) exist: a ZIP is already DEFLATE-compressed per entry, so gzip-wrapping it would compress already-compressed data for no benefit. `b.archive.tar().toGzip()` (the real `.tar.gz`) is unchanged.
@@ -503,6 +503,18 @@ function zip(adapter, opts) {
503
503
  var entryTypePolicy = _normalizeEntryTypePolicy(opts.entryTypePolicy);
504
504
  var cdCache = null;
505
505
 
506
+ // Cooperative cancellation — operators pass an AbortSignal to bound a
507
+ // large/slow archive read. Checked between entries (the natural yield
508
+ // point); a long single-entry decompress is already bounded by the
509
+ // bomb policy.
510
+ function _throwIfAborted() {
511
+ if (opts.signal && opts.signal.aborted) {
512
+ throw new ArchiveReadError("archive-read/aborted",
513
+ "archive read aborted via opts.signal" +
514
+ (opts.signal.reason !== undefined ? ": " + String(opts.signal.reason) : ""));
515
+ }
516
+ }
517
+
506
518
  async function _loadCD() {
507
519
  if (cdCache) return cdCache;
508
520
  var eocd = await _locateEocd(adapter);
@@ -512,6 +524,7 @@ function zip(adapter, opts) {
512
524
  }
513
525
 
514
526
  async function inspect() {
527
+ _throwIfAborted();
515
528
  var loaded = await _loadCD();
516
529
  _enforceBombPolicy(loaded.entries, bombPolicy);
517
530
  _emitAudit(opts, "archive.read.inspect", "success", {
@@ -539,9 +552,11 @@ function zip(adapter, opts) {
539
552
  }
540
553
 
541
554
  async function* entries() {
555
+ _throwIfAborted();
542
556
  var loaded = await _loadCD();
543
557
  _enforceBombPolicy(loaded.entries, bombPolicy);
544
558
  for (var i = 0; i < loaded.entries.length; i += 1) {
559
+ _throwIfAborted();
545
560
  yield loaded.entries[i];
546
561
  }
547
562
  }
@@ -593,6 +608,7 @@ function zip(adapter, opts) {
593
608
  var totalDecompressed = 0;
594
609
  var yielded = 0;
595
610
  for (var i = 0; i < loaded.entries.length; i += 1) {
611
+ _throwIfAborted();
596
612
  var entry = loaded.entries[i];
597
613
  if (entry.isEncrypted && !extractOpts.allowEncrypted) {
598
614
  throw new ArchiveReadError("archive-read/encrypted-entry",
@@ -644,6 +660,7 @@ function zip(adapter, opts) {
644
660
  var totalDecompressed = 0;
645
661
  try {
646
662
  for (var i = 0; i < loaded.entries.length; i += 1) {
663
+ _throwIfAborted();
647
664
  var entry = loaded.entries[i];
648
665
  // Skip directory + dangerous-by-default entry types unless the
649
666
  // entry-type policy opts in.
package/lib/auth/fal.js CHANGED
@@ -155,6 +155,18 @@ function fromAssertion(opts) {
155
155
  "fal.fromAssertion: channel must be 'front' or 'back'");
156
156
  }
157
157
  var hokBinding = opts.hokBinding;
158
+ // `bearerOnly: true` is the explicit alias for "no proof-of-possession
159
+ // binding" (hokBinding === null). It contradicts a non-null hokBinding;
160
+ // refuse the contradiction at the entry point rather than silently
161
+ // picking one — an operator who sets both has a config bug.
162
+ if (opts.bearerOnly === true) {
163
+ if (hokBinding !== undefined && hokBinding !== null) {
164
+ throw new AuthError("auth/bad-fal-opts",
165
+ "fal.fromAssertion: bearerOnly:true conflicts with hokBinding '" + hokBinding +
166
+ "' (bearerOnly forces no proof-of-possession binding)");
167
+ }
168
+ hokBinding = null;
169
+ }
158
170
  if (hokBinding !== undefined && hokBinding !== null) {
159
171
  if (hokBinding !== "mtls" && hokBinding !== "dpop" && hokBinding !== "saml-hok") {
160
172
  throw new AuthError("auth/bad-fal-opts",
@@ -175,8 +175,8 @@ function _assertAlgKtyMatch(alg, jwk) {
175
175
  else if (alg === "ML-DSA-65" || alg === "ML-DSA-87") { expectedKty = "AKP"; }
176
176
  else {
177
177
  // Unknown alg — caller's alg allowlist should have rejected first;
178
- // refuse here defensively (CVE-2026-23993 class — unknown-alg paths
179
- // that skip downstream verification).
178
+ // refuse here defensively (CWE-347 alg-confusion class — unknown-alg
179
+ // paths that skip downstream verification; cf. CVE-2026-22817).
180
180
  throw new AuthError("auth-jwt-external/unsupported-alg",
181
181
  "_assertAlgKtyMatch: alg '" + alg + "' has no defined key-type binding");
182
182
  }
@@ -336,7 +336,7 @@ async function verifyExternal(token, opts) {
336
336
 
337
337
  // Decode header + payload.
338
338
  var parts = token.split(".");
339
- // CVE-2026-29000 / CVE-2026-23993 / CVE-2026-22817 / CVE-2026-34950 —
339
+ // CVE-2026-29000 / CVE-2026-22817 / CVE-2026-34950 —
340
340
  // JWE-bypass + alg-confusion. A 5-segment compact serialization is a
341
341
  // JWE (RFC 7516); accepting it on a JWS verifier is the canonical
342
342
  // confused-deputy shape. verifyExternal is JWS-only; refuse JWE
@@ -350,7 +350,7 @@ async function verifyExternal(token, opts) {
350
350
  }); } catch (_e) { /* audit best-effort */ }
351
351
  throw new AuthError("auth-jwt-external/jwe-refused",
352
352
  "5-segment JWE token refused — verifyExternal only handles JWS " +
353
- "(JWE bypass class — CVE-2026-29000 / CVE-2026-23993 / CVE-2026-22817 / CVE-2026-34950)");
353
+ "(JWE bypass class — CVE-2026-29000 / CVE-2026-22817 / CVE-2026-34950)");
354
354
  }
355
355
  if (parts.length !== 3) {
356
356
  throw new AuthError("auth-jwt-external/malformed-jwt",
@@ -371,8 +371,9 @@ async function verifyExternal(token, opts) {
371
371
  throw new AuthError("auth-jwt-external/unknown-crit",
372
372
  "token declares 'crit' header — verifyExternal does not support critical extensions");
373
373
  }
374
- // CVE-2026-23993 refuse alg values outside the accepted list BEFORE
375
- // any key lookup. The early refusal closes the class where an
374
+ // Alg-allowlist gate (CWE-347 improper-sig-verification / CWE-757
375
+ // algorithm-downgrade) refuse alg values outside the accepted list
376
+ // BEFORE any key lookup. The early refusal closes the class where an
376
377
  // unknown / unsupported alg slips through to a downstream code path
377
378
  // that interprets it permissively. The per-listed algorithm check
378
379
  // above in the opts-validation loop refuses the OPERATOR'S allowlist
@@ -381,11 +382,11 @@ async function verifyExternal(token, opts) {
381
382
  if (opts.algorithms.indexOf(header.alg) === -1) {
382
383
  throw new AuthError("auth-jwt-external/alg-not-allowed",
383
384
  "token alg='" + header.alg + "' not in allowed list [" + opts.algorithms.join(", ") +
384
- "] (CVE-2026-23993 — refused before key lookup)");
385
+ "] (alg-allowlist gate — refused before key lookup)");
385
386
  }
386
387
  if (SUPPORTED_CLASSICAL_ALGS.indexOf(header.alg) === -1) {
387
388
  throw new AuthError("auth-jwt-external/unsupported-alg",
388
- "token alg='" + header.alg + "' is not in the verifier's supported set (CVE-2026-23993)");
389
+ "token alg='" + header.alg + "' is not in the verifier's supported set (alg-allowlist gate)");
389
390
  }
390
391
 
391
392
  // Resolve key.
package/lib/auth/oauth.js CHANGED
@@ -1008,7 +1008,7 @@ function create(opts) {
1008
1008
  throw new OAuthError("auth-oauth/no-id-token", "verifyIdToken: idToken must be a string");
1009
1009
  }
1010
1010
  var parts = idToken.split(".");
1011
- // CVE-2026-29000 / CVE-2026-22817 / CVE-2026-23993 — mirror
1011
+ // CVE-2026-29000 / CVE-2026-22817 — mirror
1012
1012
  // jwt-external's 5-segment JWE refusal. A 5-segment compact
1013
1013
  // serialization is a JWE (RFC 7516); verifyIdToken is a JWS verifier
1014
1014
  // and a JWE shape reaching here is the confused-deputy class an OP
@@ -1023,7 +1023,7 @@ function create(opts) {
1023
1023
  }); } catch (_e) { /* drop-silent — observability sink */ }
1024
1024
  throw new OAuthError("auth-oauth/jwe-refused",
1025
1025
  "5-segment JWE id_token refused — verifyIdToken only handles JWS " +
1026
- "(CVE-2026-29000 / CVE-2026-23993 / CVE-2026-22817 / CVE-2026-34950 JWE-bypass class)");
1026
+ "(CVE-2026-29000 / CVE-2026-22817 / CVE-2026-34950 JWE-bypass class)");
1027
1027
  }
1028
1028
  if (parts.length !== 3) {
1029
1029
  throw new OAuthError("auth-oauth/malformed-jwt", "ID token does not have 3 parts");
@@ -1039,13 +1039,14 @@ function create(opts) {
1039
1039
  if (!header || typeof header.alg !== "string") {
1040
1040
  throw new OAuthError("auth-oauth/malformed-jwt", "ID token header missing 'alg'");
1041
1041
  }
1042
- // CVE-2026-23993 — refuse unknown alg BEFORE any key resolution.
1042
+ // Alg-allowlist gate (CWE-347 / CWE-757) — refuse unknown alg BEFORE
1043
+ // any key resolution.
1043
1044
  // The acceptedAlgorithms list is the operator's posture; an alg
1044
1045
  // outside it never reaches the JWKS lookup or node:crypto.verify.
1045
1046
  if (acceptedAlgorithms.indexOf(header.alg) === -1) {
1046
1047
  throw new OAuthError("auth-oauth/alg-not-accepted",
1047
1048
  "ID token signed with '" + header.alg + "' which is not in the accepted-algorithm list " +
1048
- "(CVE-2026-23993 — refused before key lookup)");
1049
+ "(alg-allowlist gate — refused before key lookup)");
1049
1050
  }
1050
1051
  // RFC 7515 §4.1.11 — refuse JWS with `crit` header. Every other
1051
1052
  // verifier in the framework (jwt.js, jwt-external.js, dpop.js)
@@ -108,14 +108,14 @@ function _verifyProofJwt(proofJwt, expectedAud, expectedCNonce, expectedClientId
108
108
  throw new AuthError("auth-oid4vci/wrong-proof-typ",
109
109
  "credential issuance: proof JWT typ must be \"openid4vci-proof+jwt\" (got \"" + header.typ + "\")");
110
110
  }
111
- // CVE-2026-23993 — refuse unknown / unsupported alg BEFORE any
112
- // verify-side work. The supportedAlgs list is the issuer's posture;
111
+ // Alg-allowlist gate (CWE-347 / CWE-757) — refuse unknown / unsupported
112
+ // alg BEFORE any verify-side work. The supportedAlgs list is the issuer's posture;
113
113
  // refusing here mirrors the discipline in oauth.verifyIdToken /
114
114
  // jwt-external.verifyExternal.
115
115
  if (!header.alg || supportedAlgs.indexOf(header.alg) === -1) {
116
116
  throw new AuthError("auth-oid4vci/unsupported-proof-alg",
117
117
  "credential issuance: proof JWT alg \"" + header.alg + "\" not in issuer-supported set " +
118
- "(CVE-2026-23993 — refused before key lookup)");
118
+ "(alg-allowlist gate — refused before key lookup)");
119
119
  }
120
120
  // AUTH-5 / RFC 7515 §4.1.11 — refuse non-empty `crit`. Pre-v0.9.x
121
121
  // silently ignored, letting an attacker-controlled wallet declare
@@ -441,15 +441,15 @@ async function verify(presentation, opts) {
441
441
  "verify: malformed JWT header: " + e.message);
442
442
  }
443
443
  var alg = headerObj.alg;
444
- // CVE-2026-23993 — refuse unknown / unsupported alg BEFORE any key
445
- // resolution. The shared `_assertAlgKtyMatch` helper repeats this
444
+ // Alg-allowlist gate (CWE-347 / CWE-757) — refuse unknown / unsupported
445
+ // alg BEFORE any key resolution. The shared `_assertAlgKtyMatch` helper repeats this
446
446
  // check after the issuer key is resolved; doing it here too closes
447
447
  // the gap where an issuerKeyResolver with side effects (network
448
448
  // fetch, audit emit) would run even when the alg is unsupported.
449
449
  if (typeof alg !== "string" || SUPPORTED_ALGS.indexOf(alg) === -1) {
450
450
  throw new AuthError("auth-sd-jwt-vc/unsupported-alg",
451
451
  "verify: header alg \"" + alg + "\" not in supported set " +
452
- "(CVE-2026-23993 — refused before key lookup)");
452
+ "(alg-allowlist gate — refused before key lookup)");
453
453
  }
454
454
  // draft-ietf-oauth-sd-jwt-vc §3.1 — typ MUST be `vc+sd-jwt` (or
455
455
  // `dc+sd-jwt` for digital-credential profile). Pre-v0.9.x the absent-
package/lib/calendar.js CHANGED
@@ -354,7 +354,14 @@ function validate(jsCal) {
354
354
  * // → { "@type":"Event", uid:"a@b", updated:"2026-05-21T10:00:00Z", ... }
355
355
  */
356
356
  function fromIcal(text, opts) {
357
- var ast = safeIcal.parse(text, opts || {});
357
+ // Forward parser options to b.safeIcal.parse. Accept BOTH the
358
+ // documented nested form (`{ safeIcalOpts: { profile, caps, ... } }`)
359
+ // AND the historically-working top-level form (`{ profile: "balanced" }`)
360
+ // so neither caller regresses; the nested form wins on conflict. The
361
+ // `safeIcalOpts` wrapper key itself is stripped before forwarding.
362
+ var icalOpts = Object.assign({}, opts || {}, (opts && opts.safeIcalOpts) || {});
363
+ delete icalOpts.safeIcalOpts;
364
+ var ast = safeIcal.parse(text, icalOpts);
358
365
  var events = (ast && ast.vcalendar && ast.vcalendar.vevent) || [];
359
366
  var todos = (ast && ast.vcalendar && ast.vcalendar.vtodo) || [];
360
367
  var journals = (ast && ast.vcalendar && ast.vcalendar.vjournal) || [];
@@ -42,10 +42,11 @@ var retryHelper = require("./retry");
42
42
  * with the framework's `create(opts)` vocabulary.
43
43
  *
44
44
  * The `CIRCUIT_OPEN` error code is a pre-v1 artifact — every other
45
- * framework error class uses namespaced codes (`retry/...`). The
46
- * rename is deferred to v0.10 with a deprecation cycle so existing
47
- * operators who match `err.code === "CIRCUIT_OPEN"` aren't broken
48
- * in a patch.
45
+ * framework error class uses namespaced codes (`retry/...`). It is
46
+ * kept through the pre-1.0 line so existing operators who match
47
+ * `err.code === "CIRCUIT_OPEN"` aren't broken in a patch; the rename
48
+ * to a namespaced code lands at v1.0 alongside the namespaced-error
49
+ * sweep, with a deprecation warning shipping a minor ahead.
49
50
  *
50
51
  * @opts
51
52
  * name: string, // identifier used in audit + state-change events
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.13.9",
3
+ "version": "0.13.11",
4
4
  "description": "The Node framework that owns its stack.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
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:8b6b1445-7522-46ce-ab72-88ef073536dd",
5
+ "serialNumber": "urn:uuid:072ab39e-e89f-4967-a9fc-8a2a28ec13b8",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-27T07:12:04.477Z",
8
+ "timestamp": "2026-05-27T09:56:05.887Z",
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.13.9",
22
+ "bom-ref": "@blamejs/core@0.13.11",
23
23
  "type": "application",
24
24
  "name": "blamejs",
25
- "version": "0.13.9",
25
+ "version": "0.13.11",
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.13.9",
29
+ "purl": "pkg:npm/%40blamejs/core@0.13.11",
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.13.9",
57
+ "ref": "@blamejs/core@0.13.11",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]