@blamejs/core 0.13.20 → 0.13.22

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.22 (2026-05-27) — **`b.archive.read.zip.fromTrustedStream` reads a ZIP from a Readable — no longer an experimental stub.** fromTrustedStream was an experimental stub whose inspect / entries / extract methods threw, forcing callers to buffer the stream themselves and use the random-access reader. It now works, with the same shape as the tar trusted-stream reader: pass b.archive.adapters.trustedStream(readable) and the bytes are collected into a size-capped buffer (1 GiB hard ceiling) and read through the same bomb-cap, path-traversal, and entry-type decode as the random-access reader — so bombPolicy, guardProfile, entryTypePolicy, and audit all apply, and inspect / entries / extract / extractEntries all return data. This is a bounded-memory reader (the archive is held in memory under the ceiling), not zero-buffer streaming; a future forward-inflate walker shared with the tar reader would lift the ceiling. **Added:** *`b.archive.read.zip.fromTrustedStream` now reads — `inspect` / `entries` / `extract` / `extractEntries`* — The ZIP trusted-stream reader is implemented (was an experimental stub that threw). Pass `b.archive.adapters.trustedStream(readable)` to read a ZIP straight from a Node Readable without buffering it yourself. The stream is collected into a size-capped buffer (1 GiB ceiling, matching `b.archive.read.tar`'s trusted-stream reader) and decoded through the same adversarial-safe path as the random-access reader, so `bombPolicy` / `guardProfile` / `entryTypePolicy` / `audit` are honored on decode. Adversarial archives remain fully bomb-capped; "trusted" refers only to the source-size bound. A non-trusted-stream adapter is refused with `archive-read/bad-adapter`.
12
+
13
+ - v0.13.21 (2026-05-27) — **`b.cose.exportKey` — serialize a public key as a COSE_Key, the inverse of `b.cose.importKey`.** b.cose could import a COSE_Key (RFC 9052 §7) into a node:crypto key for verification, but had no way to produce one — so a key used with b.cose.sign could not be shipped to a verifier in COSE form without hand-building the CBOR map. b.cose.exportKey(keyObject, opts?) closes the round-trip: it serializes an EC2 (P-256 / P-384 / P-521) or OKP (Ed25519) public key as the CBOR-encoded COSE_Key map, with optional alg and kid common parameters. A private key has its public half exported; unsupported curves / key types are refused rather than emitting a COSE_Key no verifier here would accept. The bytes round-trip through b.cose.importKey, and feed the mdoc MSO / COSE_Key header / SCITT / C2PA verification-key paths. **Added:** *`b.cose.exportKey(keyObject, { alg?, kid? })` — KeyObject → COSE_Key (RFC 9052 §7)* — Serialize a `node:crypto` public key as the CBOR-encoded COSE_Key map — the inverse of `b.cose.importKey`. Supports EC2 (P-256 / P-384 / P-521) and OKP (Ed25519), the same key types `b.cose.verify` accepts; `opts.alg` (e.g. `"ES256"`) and `opts.kid` populate the COSE_Key alg (label 3) and kid (label 2) common parameters. A private key exports its public half; unsupported curves / key types throw rather than producing a COSE_Key no verifier would accept. `b.cose.importKey(b.cbor.decode(exportKey(k)))` round-trips, so a key signed with `b.cose.sign` can be shipped to a verifier as bytes — the mdoc MSO / COSE_Key header / SCITT / C2PA verification-key paths.
14
+
11
15
  - v0.13.20 (2026-05-27) — **`b.archive.wrap` can seal an archive for a tenant with no key-pair to manage — `recipient: "tenant"`.** b.archive.wrap previously sealed only to an explicit hybrid-PQC key-pair or a peer certificate; the documented recipient: "tenant" strategy threw. It now works: pass { recipient: "tenant", tenantId } and the archive is sealed under a deterministic per-tenant key derived from the vault root (SHAKE256 KDF) with XChaCha20-Poly1305, the tenant id mixed into the AEAD additional-authenticated-data so one tenant's envelope cannot be opened under another tenant's key. There is no recipient key-pair for the operator to generate, store, or rotate — b.archive.unwrap re-derives the key from the same tenantId. Rotating the vault re-keys every tenant (rotation intent is re-seal). The derivation is exposed directly as b.agent.tenant.derivedKey(tenantId, purpose) for operators who need the raw per-tenant key for their own AEAD. Requires an initialized vault. **Added:** *`b.archive.wrap` / `b.archive.unwrap` `recipient: "tenant"` — per-tenant archive sealing, no key-pair* — `b.archive.wrap(bytes, { recipient: "tenant", tenantId })` seals under a deterministic per-tenant key derived from the vault root with XChaCha20-Poly1305 (draft-irtf-cfrg-xchacha-03) and a SHAKE256 KDF (FIPS 202); the tenant id is bound into the AEAD AAD so a tenant-A envelope cannot decrypt under tenant-B's key even if an attacker swaps envelope headers. `b.archive.unwrap(sealed, { recipient: "tenant", tenantId })` (or just `{ tenantId }`) re-derives the key and recovers the bytes — no recipient key-pair to manage. The tenant envelope carries a distinct version byte so it is never fed to the hybrid-KEM decrypt path. The static-key and peer-cert recipient strategies are unchanged. · *`b.agent.tenant.derivedKey(tenantId, purpose)` — direct per-tenant key derivation* — The deterministic, domain-separated per-tenant key derivation (vault root + tenantId + purpose, SHAKE256, NUL-separated) is now exported at the module level, returning a 64-char hex key. Previously reachable only as a method on a created tenant manager; operators who need the raw key for their own AEAD can now call it directly. Throws if the vault is not initialized.
12
16
 
13
17
  - v0.13.19 (2026-05-27) — **`auditTools` export / archive / forensic-snapshot can return the bundle as bytes — no output directory for serverless / read-only filesystems.** b.auditTools.exportSlice, b.auditTools.archive, and b.auditTools.forensicSnapshot required an `out` directory to write the encrypted bundle (rows.enc + optional checkpoint.enc + manifest.json), which is unusable on a read-only or ephemeral serverless filesystem. Each now accepts `returnBytes: true` instead of `out` and returns the bundle as an in-memory `{ filename: Buffer }` map — ready to stream to object storage or over the wire with no filesystem access. `out` and `returnBytes` are mutually exclusive. The on-disk path is unchanged. The bundle's encryption (XChaCha20-Poly1305 + Argon2id), chain-proof material, and manifest checksums are identical to the written bundle, so an in-memory bundle written to disk verifies exactly as one produced by the `out` path. **Added:** *`returnBytes` on `auditTools.exportSlice` / `archive` / `forensicSnapshot` — in-memory bundles* — Pass `returnBytes: true` (and omit `out`) to get the encrypted audit bundle as an in-memory `{ filename: Buffer }` map instead of a directory write — the read-only / serverless path. `exportSlice` / `archive` return `{ manifest, files, rowCount, range }`; `forensicSnapshot` returns `{ ...manifest, files }` where `files` carries the slice's `rows.enc` + `manifest.json` plus the `forensic-snapshot.json` incident wrapper. The encryption, chain proof, and manifest checksums match the on-disk bundle byte-for-byte, so the bytes verify with `verifyBundle` once written out. `out` and `returnBytes` are mutually exclusive (passing both throws). **Fixed:** *`auditTools.forensicSnapshot` now honors the `since` window instead of capturing the entire audit history* — `forensicSnapshot` passed its `since` bound to the slice exporter under the wrong option name, so the time filter was silently dropped and the snapshot bundled every audit row regardless of `since`. The window is now applied — a snapshot scoped to an incident window contains only that window's rows. The snapshot manifest's `auditSliceFile` field, previously always undefined, now records the slice location.
package/README.md CHANGED
@@ -141,7 +141,7 @@ The framework bundles the surface a typical Node app reaches for. Every primitiv
141
141
  - **JSON / SQL / schema** — `b.safeJson` (with `maxKeys` cap defending CVE-2026-21717 V8 HashDoS), `b.safeBuffer`, `b.safeSql`, `b.safeSchema`
142
142
  - **URL + path** — `b.safeUrl` (IDN mixed-script / homograph refuse); `b.safeJsonPath` (refuses filter `?(...)`, deep-scan `$..`, script-shape `(@.x)` for safe Postgres JSONB ops)
143
143
  - **Binary codec** — `b.cbor` bounded deterministic CBOR (RFC 8949 §4.2): depth/size caps, indefinite-length + reserved-info + tag + duplicate-key refusal, `requireDeterministic` canonical-form check; the in-tree substrate under COSE / CWT / SCITT / WebAuthn attestation
144
- - **COSE messages** — `b.cose` the full RFC 9052 message-type set over `b.cbor`: COSE_Sign1 sign/verify (attached or detached payload), COSE_Encrypt0 single-recipient AEAD, COSE_Mac0 shared-key HMAC (mac0/macVerify0), plus `importKey` (COSE_Key → KeyObject). Signatures use classical ES256/384/512 + EdDSA (final COSE ids, interoperable today) plus ML-DSA-87 (PQC-forward, draft id); bounded + alg-allowlisted + crit-bypass-checked verification; AEAD ChaCha20/Poly1305 default (AES-GCM opt-in); the signed-statement substrate under SCITT / CWT / mdoc / C2PA
144
+ - **COSE messages** — `b.cose` the full RFC 9052 message-type set over `b.cbor`: COSE_Sign1 sign/verify (attached or detached payload), COSE_Encrypt0 single-recipient AEAD, COSE_Mac0 shared-key HMAC (mac0/macVerify0), plus `importKey` (COSE_Key → KeyObject) and `exportKey` (KeyObject → COSE_Key, the inverse — ship a verification key as RFC 9052 §7 bytes). Signatures use classical ES256/384/512 + EdDSA (final COSE ids, interoperable today) plus ML-DSA-87 (PQC-forward, draft id); bounded + alg-allowlisted + crit-bypass-checked verification; AEAD ChaCha20/Poly1305 default (AES-GCM opt-in); the signed-statement substrate under SCITT / CWT / mdoc / C2PA
145
145
  - **CBOR Web Token** — `b.cwt` CWT sign/verify (RFC 8392) over `b.cose`: standard-claim mapping (iss/sub/aud/exp/nbf/iat/cti) + `exp`/`nbf` clock-skew enforcement + `iss`/`aud` matching; the CBOR-native JWT for constrained / IoT / FIDO / verifiable-credential contexts
146
146
  - **Entity Attestation Token** — `b.eat` EAT sign/verify (RFC 9711) over `b.cwt`: device + software attestation claims (ueid / oemid / hwmodel / measurements / submods) with verifier-nonce freshness binding, `dbgstat` debug-status policy, and `eat_profile` pinning
147
147
  - **SCITT signed statements** — `b.scitt` sign/verify a signed, attributable claim about an artifact (signed SBOM, build attestation, release approval) over `b.cose`: the issuer + subject bind in the integrity-protected CWT_Claims header (RFC 9597); verification refuses any statement missing the iss/sub binding. The issuer side, on finalized RFCs; the transparency receipt (COSE Receipts draft) opts in on publication
@@ -51,6 +51,8 @@ var ArchiveReadError = defineClass("ArchiveReadError", { alwaysPermanent: true }
51
51
  var guardFilename = lazyRequire(function () { return require("./guard-filename"); });
52
52
  var guardArchive = lazyRequire(function () { return require("./guard-archive"); });
53
53
  var safeDecompress = lazyRequire(function () { return require("./safe-decompress"); });
54
+ var safeBuffer = lazyRequire(function () { return require("./safe-buffer"); });
55
+ var archiveAdapters = lazyRequire(function () { return require("./archive-adapters"); });
54
56
 
55
57
  // ---- Wire-format constants ------------------------------------------------
56
58
  // Aligned with the write-side `lib/archive.js`. APPNOTE.TXT § references
@@ -775,29 +777,31 @@ function zip(adapter, opts) {
775
777
  * @status experimental
776
778
  * @related b.archive.read.zip, b.archive.adapters.trustedStream
777
779
  *
778
- * Forward-scan-only ZIP reader for trusted Readable sources. No
779
- * central-directory comparison operators reaching for this primitive
780
- * are declaring they own the producer (e.g. piping their own
781
- * `b.archive.zip().toStream()` output back into a reader for round-trip
782
- * verification).
780
+ * ZIP reader for a Readable source — pass `b.archive.adapters.trustedStream(readable)`
781
+ * instead of buffering the stream yourself. The bytes are collected
782
+ * into a size-capped buffer (1 GiB hard ceiling, like the tar
783
+ * trusted-stream reader) and then read through the same bomb-cap /
784
+ * path-traversal / entry-policy decode as the random-access reader, so
785
+ * `bombPolicy`, `guardProfile`, `entryTypePolicy`, and `audit` all
786
+ * apply. "Trusted" means the source size is bounded by the operator —
787
+ * the collection ceiling is the only guard against an unbounded
788
+ * producer; adversarial archives are still fully bomb-capped on decode.
783
789
  *
784
- * NOT YET IMPLEMENTED: the streaming LFH walker is not built
785
- * `inspect()` / `entries()` / `extract()` throw
786
- * `archive-read/trusted-stream-*-deferred`, and `bombPolicy` / `audit`
787
- * are accepted but not yet honored. Re-opens when a streaming
788
- * consumer needs it. Until then, collect the stream into a buffer and
789
- * use the random-access reader, which is the supported path for both
790
- * trusted round-trip verification and adversarial input.
790
+ * The collection ceiling means this is not zero-buffer streaming (the
791
+ * whole archive is held in memory, capped); a future bounded-memory
792
+ * forward-inflate walker would lift that, shared with the tar reader.
791
793
  *
792
794
  * @opts
793
- * bombPolicy: { ... }, // reserved — not yet honored
794
- * audit: b.audit, // reserved — not yet honored
795
+ * bombPolicy: { maxEntries, maxEntryDecompressedBytes,
796
+ * maxTotalDecompressedBytes, maxExpansionRatio },
797
+ * entryTypePolicy: { ... },
798
+ * guardProfile: "strict" | "balanced" | "permissive",
799
+ * audit: b.audit,
795
800
  *
796
801
  * @example
797
- * // Supported path: buffer the stream, then read random-access.
798
- * var bytes = await someStreamToBuffer(producedZipStream);
799
- * var reader = b.archive.read.zip(b.archive.adapters.buffer(bytes));
802
+ * var reader = b.archive.read.zip.fromTrustedStream(b.archive.adapters.trustedStream(readable));
800
803
  * var entries = await reader.inspect();
804
+ * void entries;
801
805
  */
802
806
  function fromTrustedStream(adapter, opts) {
803
807
  if (!adapter || adapter.kind !== "trusted-sequential") {
@@ -805,36 +809,45 @@ function fromTrustedStream(adapter, opts) {
805
809
  "fromTrustedStream: adapter must come from b.archive.adapters.trustedStream(readable)");
806
810
  }
807
811
  opts = opts || {};
808
- var bombPolicy = _normalizeBombPolicy(opts.bombPolicy);
809
- void bombPolicy;
810
-
811
- // The streaming LFH walker is not built only the API surface +
812
- // adapter validation exist. Extraction via streaming inflate +
813
- // data-descriptor scanning re-opens when a streaming consumer needs
814
- // it; until then the supported path is to buffer the stream and use
815
- // the random-access reader (which handles both trusted round-trip
816
- // verification and adversarial input).
817
- async function inspect() {
818
- throw new ArchiveReadError("archive-read/trusted-stream-inspect-deferred",
819
- "fromTrustedStream.inspect() is not implemented — collect the stream into a buffer and " +
820
- "use b.archive.read.zip(b.archive.adapters.buffer(bytes))");
812
+
813
+ // Collect the Readable into a size-capped buffer once (tar-parity:
814
+ // boundedChunkCollector with a 1 GiB ceiling), then delegate to the
815
+ // random-access reader so the full bomb-cap / guard / audit decode
816
+ // applies. Lazy + memoized construction stays cheap and the stream
817
+ // is consumed only on the first method call.
818
+ var readerPromise = null;
819
+ function _reader() {
820
+ if (!readerPromise) {
821
+ readerPromise = (async function () {
822
+ var collector = safeBuffer().boundedChunkCollector({
823
+ maxBytes: C.BYTES.gib(1),
824
+ errorClass: ArchiveReadError,
825
+ sizeCode: "archive-read/trusted-stream-too-large",
826
+ });
827
+ for await (var chunk of adapter.readable) { collector.push(chunk); }
828
+ return zip(archiveAdapters().buffer(collector.result()), opts);
829
+ })();
830
+ }
831
+ return readerPromise;
821
832
  }
822
833
 
834
+ async function inspect() { return (await _reader()).inspect(); }
823
835
  async function* entries() {
824
- throw new ArchiveReadError("archive-read/trusted-stream-entries-deferred",
825
- "fromTrustedStream.entries() is not implemented collect into a buffer and use the random-access reader");
836
+ var r = await _reader();
837
+ for await (var e of r.entries()) { yield e; }
826
838
  }
827
-
828
- async function extract() {
829
- throw new ArchiveReadError("archive-read/trusted-stream-extract-deferred",
830
- "fromTrustedStream.extract() is not implemented collect into a buffer and use the random-access reader");
839
+ async function extract(extractOpts) { return (await _reader()).extract(extractOpts); }
840
+ async function* extractEntries(extractOpts) {
841
+ var r = await _reader();
842
+ for await (var e of r.extractEntries(extractOpts)) { yield e; }
831
843
  }
832
844
 
833
845
  return {
834
- kind: "zip-trusted-sequential",
835
- inspect: inspect,
836
- entries: entries,
837
- extract: extract,
846
+ kind: "zip-trusted-sequential",
847
+ inspect: inspect,
848
+ entries: entries,
849
+ extract: extract,
850
+ extractEntries: extractEntries,
838
851
  };
839
852
  }
840
853
 
package/lib/cose.js CHANGED
@@ -743,9 +743,15 @@ function macVerify0(coseMac0, opts) {
743
743
  // secp256k1 key be verified under ES256, breaking the COSE alg/curve
744
744
  // binding (RFC 9053). Re-add with an explicit ES256K algorithm.
745
745
  var COSE_EC2_CRV = { 1: "P-256", 2: "P-384", 3: "P-521" };
746
+ // Reverse of COSE_EC2_CRV — JWK crv name → COSE EC2 curve id, for exportKey.
747
+ var COSE_EC2_CRV_ID = { "P-256": 1, "P-384": 2, "P-521": 3 };
746
748
  var COSE_KTY_OKP = 1;
747
749
  var COSE_KTY_EC2 = 2;
748
750
  var COSE_OKP_ED25519 = 6; // allow:raw-byte-literal — COSE OKP Ed25519 crv id (RFC 9053)
751
+ // COSE_Key common-parameter labels (RFC 9052 §7.1): 1=kty, 2=kid, 3=alg.
752
+ var COSE_KEY_LABEL_KTY = 1;
753
+ var COSE_KEY_LABEL_KID = 2;
754
+ var COSE_KEY_LABEL_ALG = 3;
749
755
 
750
756
  function _coseKeyBytes(v, what) {
751
757
  if (Buffer.isBuffer(v)) return v;
@@ -804,6 +810,83 @@ function importKey(coseKey) {
804
810
  catch (e) { throw new CoseError("cose/bad-cose-key", "cose.importKey: could not import COSE_Key: " + ((e && e.message) || e)); }
805
811
  }
806
812
 
813
+ /**
814
+ * @primitive b.cose.exportKey
815
+ * @signature b.cose.exportKey(keyObject, opts?)
816
+ * @since 0.13.20
817
+ * @status stable
818
+ * @related b.cose.importKey, b.cose.verify, b.cbor.encode
819
+ *
820
+ * Serialize a <code>node:crypto</code> public key as a COSE_Key
821
+ * (RFC 9052 §7) — the CBOR-map, integer-labelled form embedded in an
822
+ * mdoc MSO, a COSE_Key header, or a SCITT / C2PA verification-key
823
+ * field. The inverse of <code>b.cose.importKey</code>: a key signed
824
+ * with <code>b.cose.sign</code> can be shipped to a verifier as bytes
825
+ * and re-imported. Returns the CBOR-encoded bytes (like the other COSE
826
+ * producers); pass the decoded map to <code>importKey</code> to round-trip.
827
+ *
828
+ * Accepts the same key types <code>importKey</code> / <code>verify</code>
829
+ * understand: EC2 (P-256 / P-384 / P-521) and OKP (Ed25519). A private
830
+ * key has its public half exported. Other curves / key types are
831
+ * refused rather than emitting a COSE_Key no verifier here would accept.
832
+ *
833
+ * @opts
834
+ * alg: string, // optional COSE alg label (e.g. "ES256") → COSE_Key label 3
835
+ * kid: Buffer | string, // optional key id → COSE_Key label 2 (bstr; string encoded UTF-8)
836
+ *
837
+ * @example
838
+ * var bytes = b.cose.exportKey(pubKey, { alg: "ES256", kid: "key-1" });
839
+ * var key = b.cose.importKey(b.cbor.decode(bytes)); // round-trips
840
+ */
841
+ function exportKey(keyObject, opts) {
842
+ opts = opts || {};
843
+ if (!keyObject || typeof keyObject.export !== "function" || typeof keyObject.type !== "string") {
844
+ throw new CoseError("cose/bad-key", "cose.exportKey: expected a node:crypto KeyObject");
845
+ }
846
+ // A private key exports its public half — a COSE_Key here is a
847
+ // verification key, never the secret.
848
+ var pub = keyObject.type === "private" ? nodeCrypto.createPublicKey(keyObject) : keyObject;
849
+ var jwk;
850
+ try { jwk = pub.export({ format: "jwk" }); }
851
+ catch (e) { throw new CoseError("cose/bad-key", "cose.exportKey: could not export key to JWK: " + ((e && e.message) || e)); }
852
+
853
+ var coseKey = new Map();
854
+ if (jwk.kty === "OKP") {
855
+ if (jwk.crv !== "Ed25519") {
856
+ throw new CoseError("cose/unsupported-key", "cose.exportKey: only OKP curve Ed25519 is supported (got " + jwk.crv + ")");
857
+ }
858
+ coseKey.set(COSE_KEY_LABEL_KTY, COSE_KTY_OKP);
859
+ coseKey.set(-1, COSE_OKP_ED25519);
860
+ coseKey.set(-2, Buffer.from(jwk.x, "base64url"));
861
+ } else if (jwk.kty === "EC") {
862
+ var crvId = COSE_EC2_CRV_ID[jwk.crv];
863
+ if (!crvId) {
864
+ throw new CoseError("cose/unsupported-key", "cose.exportKey: unsupported EC curve " + jwk.crv + " (only P-256 / P-384 / P-521)");
865
+ }
866
+ coseKey.set(COSE_KEY_LABEL_KTY, COSE_KTY_EC2);
867
+ coseKey.set(-1, crvId);
868
+ coseKey.set(-2, Buffer.from(jwk.x, "base64url"));
869
+ coseKey.set(-3, Buffer.from(jwk.y, "base64url"));
870
+ } else {
871
+ throw new CoseError("cose/unsupported-key", "cose.exportKey: kty must be OKP or EC (got " + jwk.kty + ")");
872
+ }
873
+
874
+ if (opts.kid !== undefined) {
875
+ var kid = Buffer.isBuffer(opts.kid) ? opts.kid
876
+ : (typeof opts.kid === "string" ? Buffer.from(opts.kid, "utf8") : null);
877
+ if (!kid) throw new CoseError("cose/bad-kid", "cose.exportKey: opts.kid must be a Buffer or string");
878
+ coseKey.set(COSE_KEY_LABEL_KID, kid);
879
+ }
880
+ if (opts.alg !== undefined) {
881
+ var algId = ALG_NAME_TO_ID[opts.alg];
882
+ if (algId === undefined) {
883
+ throw new CoseError("cose/unknown-alg", "cose.exportKey: opts.alg '" + opts.alg + "' not recognized");
884
+ }
885
+ coseKey.set(COSE_KEY_LABEL_ALG, algId);
886
+ }
887
+ return cbor.encode(coseKey);
888
+ }
889
+
807
890
  module.exports = {
808
891
  sign: sign,
809
892
  verify: verify,
@@ -812,6 +895,7 @@ module.exports = {
812
895
  mac0: mac0,
813
896
  macVerify0: macVerify0,
814
897
  importKey: importKey,
898
+ exportKey: exportKey,
815
899
  ALGORITHMS: ALG_NAME_TO_ID,
816
900
  MAC_ALGORITHMS: HMAC_NAME_TO_ID,
817
901
  COSE_MAC0_TAG: COSE_MAC0_TAG,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.13.20",
3
+ "version": "0.13.22",
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:aca0caec-3bdf-4b4b-bfd8-436286cc5bbf",
5
+ "serialNumber": "urn:uuid:81d23e48-6a96-4d2b-ac47-bada0b15cf1f",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-27T22:48:58.698Z",
8
+ "timestamp": "2026-05-28T00:00:09.259Z",
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.20",
22
+ "bom-ref": "@blamejs/core@0.13.22",
23
23
  "type": "application",
24
24
  "name": "blamejs",
25
- "version": "0.13.20",
25
+ "version": "0.13.22",
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.20",
29
+ "purl": "pkg:npm/%40blamejs/core@0.13.22",
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.20",
57
+ "ref": "@blamejs/core@0.13.22",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]