@blamejs/core 0.13.42 → 0.13.43
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/LTS-CALENDAR.md +6 -2
- package/lib/ai-content-detect.js +4 -3
- package/lib/archive-read.js +10 -7
- package/lib/break-glass.js +1 -1
- package/lib/cms-codec.js +10 -9
- package/lib/mail-crypto-smime.js +10 -6
- package/lib/mtls-ca.js +2 -2
- package/lib/safe-archive.js +8 -7
- package/package.json +1 -1
- package/sbom.cdx.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.13.x
|
|
10
10
|
|
|
11
|
+
- v0.13.43 (2026-05-29) — **LTS window stated consistently as 24 months, experimental primitives declared semver-exempt, and stale version references cleaned up.** Documentation and operator-facing string hygiene ahead of the 1.0 stability contract. The LTS support window is now stated as 24 months everywhere (GOVERNANCE.md and the LTS calendar previously disagreed — 24 vs 18). The LTS calendar gains an explicit clause that primitives marked experimental are exempt from the stability/LTS contract, so operators can tell at a glance which surfaces may change between minors. Several error messages and doc blocks that pinned to long-past version numbers ("lands in v0.10.9", "not supported in v0.12.7", "ships in v0.6.45+") are restated version-agnostically with their escape hatch, and the S/MIME module now points operators at the live PGP encrypt/decrypt path for confidentiality today. No API or behavior changes. **Changed:** *LTS support window is consistently 24 months* — `GOVERNANCE.md` promised a 24-month LTS window while `LTS-CALENDAR.md` and `SECURITY.md` stated 18 — a six-month contradiction in the single most load-bearing number of the support contract. All three now state 24 months of security-only patches per major. The calendar table and the supported-versions prose are aligned. · *Experimental primitives are declared exempt from the stability contract* — `LTS-CALENDAR.md` now states explicitly that primitives documented as experimental (shown as "experimental" on their wiki page, and via the `experimental` segment in namespaces like `b.jose.jwe.experimental`) are not covered by the stability contract or the LTS window — they may change signature, behavior, or wire format, or be removed, in any minor without a deprecation cycle. This lets the framework ship primitives that track in-flight standards without freezing an unsettled format, and tells operators precisely which surfaces are not yet frozen. **Fixed:** *Stale version references removed from operator-facing errors and docs* — Error messages and documentation that pinned to long-past versions are restated version-agnostically with the relevant escape hatch: ZIP64 and unsupported-compression errors in archive reading, the CMS AuthEnvelopedData / fielded-decoder notes, the mTLS CRL-engine error, the safe-archive format-detection summary (which also now correctly lists the supported zip / tar / tar.gz set rather than claiming only zip), and the AI-content IPTC-reader note. None changed behavior; they no longer read as broken promises against the published version history. · *S/MIME confidentiality deferral points to the working PGP path* — `b.mail.crypto.smime` ships sign + verify; encrypt/decrypt is deferred. The deferral note previously cited an open-ended internal condition; it now names the escape hatch directly — use `b.mail.crypto.pgp.encrypt` / `decrypt` for mail confidentiality today — and states the concrete trigger that would re-open S/MIME-specific (X.509-recipient) encryption. · *Governance doc no longer references an internal file operators cannot see* — `GOVERNANCE.md` cited a rule number in a contributor-only file that does not ship in the repository. The deprecation-policy statement is now self-contained.
|
|
12
|
+
|
|
11
13
|
- v0.13.42 (2026-05-29) — **S/MIME trust-chain validation binds the leaf to the key that verified the signature.** When b.mail.crypto.smime.verify is given trust anchors, it validates the supplied certificate chain — but it picked the chain leaf unconditionally (the first cert) and never tied it to signerPublicKey, the key that actually verified the signature. A SignedData blob could therefore carry a validly-chained certificate for one identity while the signature was verified under an unrelated key, and the chain-validated result would imply a cert↔signer binding the code never made. Chain validation now selects the leaf as the certificate whose public key matches signerPublicKey, and refuses (signer-not-in-chain) when no certificate in the chain carries that key — so a chain-validated signature is bound to the cert it claims. **Security:** *Trust-chain leaf is bound to the verified signer key* — `smime.verify({ trustAnchorCertsPem })` validated the supplied chain starting from `chain[0]` without checking that the leaf's public key was the one that verified the signature (the operator-supplied `signerPublicKey`). A crafted `SignedData` could pair a validly-chained certificate for identity A with a signature verified under an unrelated key, and the chain-valid result would assert a binding that didn't hold. The chain walk now selects the leaf as the certificate whose public key equals `signerPublicKey` (matched against the certificate's SPKI, raw key or full-encoding form), and throws `mail-crypto/smime/signer-not-in-chain` when no certificate in `SignedData.certificates` carries that key. A certificate whose key cannot be extracted is treated as a non-match, so validation fails closed rather than trusting an unverifiable binding.
|
|
12
14
|
|
|
13
15
|
- v0.13.41 (2026-05-29) — **Agent registry reads can be tenant-scoped; compliance-erasure docs clarify actor is an audit field.** The agent orchestrator's registry reads (list and lookup) gated only on the flat agent-registry:read scope, so any holder could enumerate every tenant's agents and resolve a handle to one — even though the event bus already scopes subscribe and delivery by tenant. The orchestrator now mirrors that: with the new tenantScope option enabled, list returns only the actor's own tenant's agents and lookup refuses a cross-tenant name, unless the actor holds the framework cross-tenant-admin scope. Off by default, so single-tenant deployments are unaffected. Separately, the subject-erasure docs now state explicitly that the recorded actor is an audit field, not authentication — the caller must be authorized upstream. **Added:** *Tenant-scoped agent registry reads (opts.tenantScope)* — `b.agent.orchestrator.create({ tenantScope: true })` now scopes `list` and `lookup` to the calling actor's tenant: `list` filters out agents in other tenants and `lookup` returns null for a cross-tenant name, unless the actor holds the cross-tenant-admin scope (`b.agent.tenant.CROSS_TENANT_ADMIN_SCOPE`). This closes a cross-tenant metadata-enumeration and handle-acquisition path — `agent-registry:read` alone no longer exposes other tenants' agents — and mirrors the tenant scoping the event bus enforces on subscribe and delivery. The option defaults off; existing single-tenant orchestrators behave exactly as before. The `tenantId` argument to `list` remains a convenience filter, distinct from this authorization boundary. **Changed:** *Subject-erasure docs clarify the actor is an audit field, not authentication* — `b.subject.erase` and `b.subject.eraseHard` gate the deletion on operator acknowledgements and the legal-hold registry, not on caller identity. Their documentation now states explicitly that the recorded `actor` is an audit-record field, not authentication — the caller MUST be authenticated and authorized by the route before invoking. No behavior change; this removes an implicit assumption that could otherwise be read as the primitive authorizing the call.
|
package/LTS-CALENDAR.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# LTS calendar
|
|
2
2
|
|
|
3
3
|
`@blamejs/core` ships on a published major cadence. Each major receives
|
|
4
|
-
**
|
|
4
|
+
**24 months of security-only patches** starting the day the next major is
|
|
5
5
|
published. Feature backports are not promised.
|
|
6
6
|
|
|
7
7
|
| Version | First release | Security patches through | Node minimum | KEM | Cipher | KDF | Sigs |
|
|
8
8
|
|---------------|---------------|-----------------------------|---------------|----------------------|-----------------------|----------|-----------------------|
|
|
9
9
|
| `v0.x` (pre-1.0) | 2026-04-25 | until v1.0 ships | 24 | ML-KEM-1024 + P-384 | XChaCha20-Poly1305 | SHAKE256 | SLH-DSA-SHAKE-256f |
|
|
10
|
-
| `v1.x` | TBD | first release +
|
|
10
|
+
| `v1.x` | TBD | first release + 24 months | current LTS | ML-KEM-1024 + P-384 | XChaCha20-Poly1305 | SHAKE256 | SLH-DSA-SHAKE-256f |
|
|
11
11
|
|
|
12
12
|
## What "security patches" means
|
|
13
13
|
|
|
@@ -27,3 +27,7 @@ The "Node minimum" column is the lowest Node major the framework supports for th
|
|
|
27
27
|
## Pre-1.0 caveat
|
|
28
28
|
|
|
29
29
|
`v0.x` has no LTS commitment. Every release may change something operators depend on; the algorithm posture is intentionally evolving. Read [CHANGELOG.md](CHANGELOG.md) before upgrading across more than a few patches at a time. The LTS calendar takes effect at v1.0.
|
|
30
|
+
|
|
31
|
+
## Experimental primitives are exempt
|
|
32
|
+
|
|
33
|
+
Primitives documented `@status experimental` (shown as "experimental" on each wiki page, and via the `experimental` segment in namespaces such as `b.jose.jwe.experimental`) are **not** covered by the stability contract or the LTS window. They may change signature, behavior, or wire format — or be removed — in any minor, without the deprecation cycle that stable primitives get. This applies on the LTS line too. The exemption exists so the framework can ship primitives that track in-flight standards (draft RFCs, pre-IANA codepoints, newly published W3C surfaces) without freezing an unsettled format for a major's full support window. A primitive graduates to stable by dropping the `@status experimental` marker in a release whose notes call out the graduation.
|
package/lib/ai-content-detect.js
CHANGED
|
@@ -30,9 +30,10 @@
|
|
|
30
30
|
* IPTC `digitalSourceType` PhotoMetadata reading is forward-watch —
|
|
31
31
|
* the framework ships no XMP / EXIF parser yet, so operators that
|
|
32
32
|
* want IPTC detection pre-parse with their tool of choice and pass
|
|
33
|
-
* the field via `opts.ipmd`. AB-853 names C2PA as "widely adopted"
|
|
34
|
-
* IPTC PhotoMetadata reader
|
|
35
|
-
* decision
|
|
33
|
+
* the field via `opts.ipmd`. AB-853 names C2PA as "widely adopted".
|
|
34
|
+
* A built-in IPTC PhotoMetadata reader is deferred pending a vendoring
|
|
35
|
+
* decision for an XMP/EXIF parser; the `opts.ipmd` escape hatch covers
|
|
36
|
+
* the gap until then.
|
|
36
37
|
*
|
|
37
38
|
* @card
|
|
38
39
|
* Inbound provenance detector — composes C2PA verify + CAC implicit-label parser + operator-supplied IPTC field, returns a normalized report for AB-853 / EU AI Act Art. 50 / CAC disclosure UIs.
|
package/lib/archive-read.js
CHANGED
|
@@ -214,10 +214,11 @@ async function _readCentralDirectory(adapter, eocd) {
|
|
|
214
214
|
"multi-disk archives are not supported (diskNumber=" + eocd.diskNumber + ")");
|
|
215
215
|
}
|
|
216
216
|
if (eocd.totalEntries === 0xffff || eocd.cdSize === 0xffffffff || eocd.cdOffset === 0xffffffff) {
|
|
217
|
-
// ZIP64 sentinel —
|
|
218
|
-
//
|
|
217
|
+
// ZIP64 sentinel — unsupported. Archives at >4 GiB / >65535 entries
|
|
218
|
+
// use tar instead (the escape hatch); ZIP64 read support is deferred
|
|
219
|
+
// until an operator surfaces a need.
|
|
219
220
|
throw new ArchiveReadError("archive-read/zip64-unsupported",
|
|
220
|
-
"ZIP64 archives are
|
|
221
|
+
"ZIP64 archives are unsupported (operators at >4 GiB / >65535 entries should switch to tar)");
|
|
221
222
|
}
|
|
222
223
|
if (eocd.cdSize === 0 || eocd.totalEntries === 0) {
|
|
223
224
|
return [];
|
|
@@ -256,7 +257,7 @@ async function _readCentralDirectory(adapter, eocd) {
|
|
|
256
257
|
}
|
|
257
258
|
if (compressedSize === 0xffffffff || uncompressedSize === 0xffffffff || lfhOffset === 0xffffffff) {
|
|
258
259
|
throw new ArchiveReadError("archive-read/zip64-unsupported",
|
|
259
|
-
"central directory entry " + n + " carries ZIP64 sentinel sizes (
|
|
260
|
+
"central directory entry " + n + " carries ZIP64 sentinel sizes (unsupported — use tar for >4 GiB / >65535 entries)");
|
|
260
261
|
}
|
|
261
262
|
// ZIP names are CP437 or UTF-8 (per FLAG_UTF8_NAME bit). Decode
|
|
262
263
|
// as UTF-8 unconditionally — Codex P2 territory if operators in
|
|
@@ -425,7 +426,7 @@ async function _decompressEntry(adapter, entry, dataStart, bombPolicy) {
|
|
|
425
426
|
}
|
|
426
427
|
throw new ArchiveReadError("archive-read/unsupported-method",
|
|
427
428
|
"entry " + JSON.stringify(entry.name) + " uses method=" + entry.method +
|
|
428
|
-
" — only STORE (0) and DEFLATE (8) supported
|
|
429
|
+
" — only STORE (0) and DEFLATE (8) are supported");
|
|
429
430
|
}
|
|
430
431
|
|
|
431
432
|
// ---- Public read.zip factory ---------------------------------------------
|
|
@@ -668,8 +669,10 @@ function zip(adapter, opts) {
|
|
|
668
669
|
// entry-type policy opts in.
|
|
669
670
|
if (entry.isEncrypted && !extractOpts.allowEncrypted) {
|
|
670
671
|
throw new ArchiveReadError("archive-read/encrypted-entry",
|
|
671
|
-
"entry " + JSON.stringify(entry.name) + " is encrypted — " +
|
|
672
|
-
"
|
|
672
|
+
"entry " + JSON.stringify(entry.name) + " is encrypted — this " +
|
|
673
|
+
"low-level reader does not decrypt; use b.safeArchive for " +
|
|
674
|
+
"encrypted-archive handling, or pass allowEncrypted to extract " +
|
|
675
|
+
"the raw entry");
|
|
673
676
|
}
|
|
674
677
|
var typeRefusal = _enforceEntryTypePolicy(entry, entryTypePolicy);
|
|
675
678
|
if (typeRefusal) {
|
package/lib/break-glass.js
CHANGED
|
@@ -523,7 +523,7 @@ function _validatePolicySet(table, opts) {
|
|
|
523
523
|
"' not in allowed factors [" + ALLOWED_FACTORS.join(",") + "]");
|
|
524
524
|
}
|
|
525
525
|
}
|
|
526
|
-
// Model B (cryptographic mode)
|
|
526
|
+
// Model B (cryptographic mode). When enabled,
|
|
527
527
|
// glass-locked columns must be encrypted with `b.breakGlass.encryptCell`
|
|
528
528
|
// at write time (the framework can't auto-encrypt at write because
|
|
529
529
|
// policy-set may post-date existing data; operators run the migration
|
package/lib/cms-codec.js
CHANGED
|
@@ -42,15 +42,16 @@
|
|
|
42
42
|
* refuses EnvelopedData and accepts only the §5083 ContentInfo
|
|
43
43
|
* OID. Cheap escape hatch: operators on such a peer compose
|
|
44
44
|
* `b.asn1Der` directly to rewrap an EnvelopedData blob into an
|
|
45
|
-
* AuthEnvelopedData ContentInfo.
|
|
46
|
-
*
|
|
47
|
-
*
|
|
45
|
+
* AuthEnvelopedData ContentInfo. A built-in encode path is deferred
|
|
46
|
+
* until an interop case requires a peer that refuses EnvelopedData;
|
|
47
|
+
* the `b.asn1Der` rewrap covers the gap until then.
|
|
48
48
|
* - **`b.cms.decode` parse-tree of inner SignedData / EnvelopedData**
|
|
49
|
-
* beyond the ContentInfo wrapper.
|
|
49
|
+
* beyond the ContentInfo wrapper. `b.cms.decode` returns the inner
|
|
50
50
|
* SEQUENCE bytes as `content` (an asn1-der node); callers that
|
|
51
|
-
* need fielded access walk it via `b.asn1Der.readSequence`.
|
|
52
|
-
* fielded decoders
|
|
53
|
-
*
|
|
51
|
+
* need fielded access walk it via `b.asn1Der.readSequence`. Built-in
|
|
52
|
+
* fielded decoders are deferred until they're actually consumed by a
|
|
53
|
+
* shipping primitive; the `b.asn1Der.readSequence` walk is the escape
|
|
54
|
+
* hatch until then.
|
|
54
55
|
*
|
|
55
56
|
* Refusal posture:
|
|
56
57
|
*
|
|
@@ -302,8 +303,8 @@ function encodeEnvelopedData(opts) {
|
|
|
302
303
|
* string (e.g. `"1.2.840.113549.1.7.2"` for SignedData) and
|
|
303
304
|
* `content` is the inner asn1-der node (SignedData / EnvelopedData /
|
|
304
305
|
* other) — operators walk it via `b.asn1Der.readSequence`. Fielded
|
|
305
|
-
* decoders for SignedData / EnvelopedData
|
|
306
|
-
*
|
|
306
|
+
* decoders for SignedData / EnvelopedData are deferred; the
|
|
307
|
+
* `b.asn1Der.readSequence` walk is the escape hatch until then.
|
|
307
308
|
*
|
|
308
309
|
* Refuses input past `opts.maxBytes` (default 64 MiB), top-level
|
|
309
310
|
* non-SEQUENCE shapes, missing OID + [0] EXPLICIT child pair.
|
package/lib/mail-crypto-smime.js
CHANGED
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
* @card
|
|
10
10
|
* S/MIME 4.0 sign + verify (PQC-first ML-DSA / SLH-DSA signers) on
|
|
11
11
|
* the b.cms substrate. RFC 8551 multipart/signed with RFC 5652
|
|
12
|
-
* SignedData
|
|
13
|
-
*
|
|
12
|
+
* SignedData. Confidentiality (encrypt/decrypt) is deferred — use
|
|
13
|
+
* `b.mail.crypto.pgp.encrypt`/`decrypt` today; S/MIME-specific
|
|
14
|
+
* (X.509-recipient) encryption re-opens when an operator surfaces a
|
|
15
|
+
* peer that requires it, with the EFAIL defenses below applied then.
|
|
14
16
|
*
|
|
15
17
|
* @intro
|
|
16
18
|
* S/MIME 4.0 (RFC 8551, replacing RFC 5751) `multipart/signed;
|
|
@@ -112,10 +114,12 @@ var ALLOWED_HASHES = ["sha256", "sha384", "sha512"];
|
|
|
112
114
|
var REFUSED_HASHES = ["md5", "sha1"]; // allow:raw-byte-literal — SHAttered / RFC 8551 §2.5
|
|
113
115
|
|
|
114
116
|
// PROFILES + COMPLIANCE_POSTURES — the framework's standard cross-
|
|
115
|
-
// primitive contract. sign() and verify()
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
117
|
+
// primitive contract. sign() and verify() read these to determine which
|
|
118
|
+
// hash + RSA-bit floors apply per operator posture. Confidentiality
|
|
119
|
+
// (encrypt/decrypt) is deferred — b.mail.crypto.pgp.encrypt/decrypt is the
|
|
120
|
+
// confidentiality path today; if S/MIME-specific X.509-recipient
|
|
121
|
+
// encryption is added, it composes the same set with the @intro EFAIL
|
|
122
|
+
// defenses applied.
|
|
119
123
|
var PROFILES = ["strict", "balanced", "permissive"];
|
|
120
124
|
var COMPLIANCE_POSTURES = {
|
|
121
125
|
hipaa: "strict",
|
package/lib/mtls-ca.js
CHANGED
|
@@ -517,8 +517,8 @@ function create(opts) {
|
|
|
517
517
|
opts3 = opts3 || {};
|
|
518
518
|
if (typeof engine.generateCrl !== "function") {
|
|
519
519
|
throw new MtlsCaError("mtls-ca/engine-no-crl",
|
|
520
|
-
"configured engine does not implement generateCrl(); the
|
|
521
|
-
"engine
|
|
520
|
+
"configured engine does not implement generateCrl(); use the " +
|
|
521
|
+
"framework's bundled CA engine, which supports it");
|
|
522
522
|
}
|
|
523
523
|
var ca = await initCA();
|
|
524
524
|
var revocations = _loadRevocations().revocations;
|
package/lib/safe-archive.js
CHANGED
|
@@ -22,10 +22,11 @@
|
|
|
22
22
|
* pipeline manually.
|
|
23
23
|
*
|
|
24
24
|
* Format auto-detection sniffs the first ~512 bytes for magic
|
|
25
|
-
* signatures
|
|
26
|
-
*
|
|
27
|
-
* wrapped
|
|
28
|
-
*
|
|
25
|
+
* signatures: ZIP (LFH magic `0x04034b50` + EOCD magic `0x06054b50`),
|
|
26
|
+
* tar (`ustar` at offset 257), gzip / tar.gz (RFC 1952 magic), and
|
|
27
|
+
* `b.crypto.encryptPacked`-wrapped envelopes (auto-unwrapped before
|
|
28
|
+
* format detection). Unrecognized inputs are flagged
|
|
29
|
+
* `safe-archive/format-unsupported`.
|
|
29
30
|
*
|
|
30
31
|
* The orchestrator refuses the WHOLE archive on any single critical
|
|
31
32
|
* guard issue — no partial extraction. Cleanup is `fs.rm`-recursive
|
|
@@ -148,7 +149,7 @@ async function _collectSourceBytes(source) {
|
|
|
148
149
|
* @opts
|
|
149
150
|
* source: b.archive.adapters.* | Buffer | string,
|
|
150
151
|
* destination: string (target directory; created if missing),
|
|
151
|
-
* format: "auto" | "zip"
|
|
152
|
+
* format: "auto" | "zip" | "tar" | "tar.gz",
|
|
152
153
|
* bombPolicy: b.guardArchive.zipBombPolicy(...) | { ... },
|
|
153
154
|
* entryTypePolicy: b.guardArchive.entryTypePolicy(...) | { ... },
|
|
154
155
|
* guardProfile: "strict" | "balanced" | "permissive" | "hipaa" | ...,
|
|
@@ -275,8 +276,8 @@ async function extract(opts) {
|
|
|
275
276
|
});
|
|
276
277
|
} else {
|
|
277
278
|
throw new SafeArchiveError("safe-archive/format-unsupported",
|
|
278
|
-
"extract: format=" + JSON.stringify(format) + " —
|
|
279
|
-
"
|
|
279
|
+
"extract: format=" + JSON.stringify(format) + " — supported formats are " +
|
|
280
|
+
"zip, tar, tar.gz; b.crypto.encryptPacked-wrapped archives are auto-unwrapped first");
|
|
280
281
|
}
|
|
281
282
|
var result = await reader.extract({
|
|
282
283
|
destination: opts.destination,
|
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:d368c000-a7b7-493e-bb55-a28c08371f7e",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-
|
|
8
|
+
"timestamp": "2026-05-30T00:14:53.721Z",
|
|
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.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.13.43",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.13.
|
|
25
|
+
"version": "0.13.43",
|
|
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.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.13.43",
|
|
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.
|
|
57
|
+
"ref": "@blamejs/core@0.13.43",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|