@blamejs/blamejs-shop 0.0.126 → 0.0.128

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.
Files changed (33) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +5 -1
  3. package/lib/admin.js +113 -0
  4. package/lib/returns.js +51 -0
  5. package/lib/storefront.js +339 -0
  6. package/lib/vendor/MANIFEST.json +3 -3
  7. package/lib/vendor/blamejs/CHANGELOG.md +14 -0
  8. package/lib/vendor/blamejs/README.md +6 -0
  9. package/lib/vendor/blamejs/SECURITY.md +4 -0
  10. package/lib/vendor/blamejs/api-snapshot.json +424 -2
  11. package/lib/vendor/blamejs/index.js +6 -0
  12. package/lib/vendor/blamejs/lib/cose.js +547 -0
  13. package/lib/vendor/blamejs/lib/cwt.js +244 -0
  14. package/lib/vendor/blamejs/lib/eat.js +240 -0
  15. package/lib/vendor/blamejs/lib/scitt.js +243 -0
  16. package/lib/vendor/blamejs/lib/tsa.js +688 -0
  17. package/lib/vendor/blamejs/lib/vc.js +328 -0
  18. package/lib/vendor/blamejs/package.json +1 -1
  19. package/lib/vendor/blamejs/release-notes/v0.12.33.json +31 -0
  20. package/lib/vendor/blamejs/release-notes/v0.12.34.json +18 -0
  21. package/lib/vendor/blamejs/release-notes/v0.12.35.json +22 -0
  22. package/lib/vendor/blamejs/release-notes/v0.12.36.json +18 -0
  23. package/lib/vendor/blamejs/release-notes/v0.12.37.json +27 -0
  24. package/lib/vendor/blamejs/release-notes/v0.12.38.json +18 -0
  25. package/lib/vendor/blamejs/release-notes/v0.12.39.json +18 -0
  26. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +24 -0
  27. package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +213 -0
  28. package/lib/vendor/blamejs/test/layer-0-primitives/cwt.test.js +137 -0
  29. package/lib/vendor/blamejs/test/layer-0-primitives/eat.test.js +111 -0
  30. package/lib/vendor/blamejs/test/layer-0-primitives/scitt.test.js +158 -0
  31. package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +373 -0
  32. package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +188 -0
  33. package/package.json +1 -1
@@ -8,6 +8,20 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.12.x
10
10
 
11
+ - v0.12.39 (2026-05-24) — **`b.vc` — W3C Verifiable Credentials 2.0 (issue / verify, JOSE + COSE securing).** Issue and verify W3C Verifiable Credentials (VC Data Model 2.0, a W3C Recommendation) secured per Securing Verifiable Credentials using JOSE and COSE (VC-JOSE-COSE, also a W3C Recommendation, May 2025). A verifiable credential is a tamper-evident, signed set of claims an issuer makes about a subject — a diploma, a membership, a license, an age assertion. Two securing mechanisms are supported, both signing the credential itself (no JWT/CWT claims wrapper): JOSE produces a compact JWS with the vc+jwt media type, signed with ES256/384/512 or EdDSA; COSE produces a COSE_Sign1 (application/vc+cose) over b.cose, which also accepts ML-DSA-87 for PQC-forward deployments. b.vc.verify auto-detects the form from the input, requires an algorithm allowlist, always refuses the JOSE none algorithm, re-checks the VCDM 2.0 structural rules, and enforces the validFrom / validUntil window. This is the W3C credential model, distinct from the IETF SD-JWT VC already at b.auth.sdJwtVc. Composes b.cose; no new runtime dependency. **Added:** *`b.vc.issue(credential, opts)` / `b.vc.verify(secured, opts)`* — `issue` validates the credential against the VCDM 2.0 structural rules (the `credentials/v2` context first, a `VerifiableCredential` type, an issuer, a credential subject) and signs it: `securing: "jose"` returns a compact JWS string (`typ` header `vc+jwt`), `securing: "cose"` returns COSE_Sign1 bytes (`typ` header `application/vc+cose`, content type `application/vc`) via `b.cose`. The credential is the exact signed payload — no JWT/CWT claims are injected. `verify` auto-detects the securing form from the input (compact-JWS string vs. COSE_Sign1 bytes), verifies the signature against the mandatory `opts.algorithms` allowlist (the JOSE `none` algorithm is always refused), re-checks the structural rules, enforces the `validFrom` / `validUntil` window against `opts.at` (default now; must be a valid Date), and optionally matches `opts.expectedIssuer` against the credential issuer id. Returns `{ credential, securing, alg, issuer }`.
12
+
13
+ - v0.12.38 (2026-05-24) — **`b.tsa` — RFC 3161 trusted timestamping client (build / parse / verify).** A timestamp authority binds a hash of your data to a trusted time, producing a token that proves the data existed at that instant — timestamp a release artifact, an audit-log checkpoint, a b.scitt signed statement, or a contract. b.tsa is the requester/verifier side of RFC 3161: buildRequest produces the DER TimeStampReq (the message imprint plus an optional nonce and a cert request), parseResponse reads the TimeStampResp (PKIStatus, failure-info bits, and the token), and verifyToken checks a token against your data and returns the asserted time. Verification is done in full per §2.4.2 / §2.3: the token is a CMS SignedData (b.cms) whose eContentType must be id-ct-TSTInfo; the message imprint must equal the hash of your data (constant-time); a sent nonce must round-trip; the signer certificate's extendedKeyUsage must be a critical, sole id-kp-timeStamping; and the CMS signature over the signed attributes must verify after the messageDigest attribute is matched to the recomputed eContent digest. An optional trust-anchor set verifies the certificate chain and validity at the asserted time. The HTTP transport to the TSA is the operator's to make. Composes b.cms and the in-tree ASN.1 DER codec; no new runtime dependency. **Added:** *`b.tsa.buildRequest(data, opts?)` / `b.tsa.parseResponse(der)` / `b.tsa.verifyToken(token, opts)`* — `buildRequest` returns `{ der, nonce, hashAlg, messageImprint }`; the imprint hash defaults to SHA-512 and may be SHA-256/384/512 or SHA3-256/512, a random 64-bit nonce and a certificate request are included by default, and a pre-hashed input is accepted with `hashed: true`. `parseResponse` returns `{ granted, status, statusString, failInfo, token }`, decoding the PKIFailureInfo bits for a non-granted response rather than throwing. `verifyToken` enforces the imprint match (`opts.data` or `opts.hash`), the nonce round-trip, the critical/sole `id-kp-timeStamping` EKU, and the CMS signature, returning `{ genTime, policy, serialHex, accuracy, hashAlg, signerCertPem }`; pass `opts.trustAnchorsPem` to also verify the certificate chain and validity at the asserted time. Timestamp tokens are third-party artifacts, so verification accepts the classical RSA (PKCS#1 v1.5 and PSS) and ECDSA-over-SHA-2 signatures that public TSAs emit — the same consume-what-exists posture as `b.cose` verification, not a framework signing default.
14
+
15
+ - v0.12.37 (2026-05-24) — **`b.scitt.signStatement` / `b.scitt.verifyStatement` — SCITT signed statements over COSE (RFC 9052 + RFC 9597).** A SCITT signed statement is a signed, attributable claim about an artifact — a signed SBOM, a build attestation, a release approval. It is a COSE_Sign1 (b.cose) whose integrity-protected CWT_Claims header (label 15, RFC 9597) binds the issuer (who makes the statement) and the subject (the artifact it is about); the artifact, or a hash/reference to it, is the payload. signStatement places iss/sub in the protected header and declares the payload media type; verifyStatement checks the COSE signature (the algorithm allowlist is mandatory) and refuses any statement that lacks the iss/sub binding, with optional expected-issuer/subject matching. Signing uses the same algorithms as b.cose — classical ES256/384/512 + EdDSA (final COSE ids, interoperable today) plus ML-DSA-87 (PQC-forward). This is the issuer side of SCITT, buildable today on finalized RFCs; the transparency receipt (an inclusion proof from a transparency service, the COSE Receipts draft) is not yet shipped — a statement produced here is the input a transparency service registers, and the receipt format is the part still in flux. It opts in when COSE Receipts publishes. **Added:** *`b.scitt.signStatement(payload, opts)` / `b.scitt.verifyStatement(statement, opts)`* — `signStatement` produces a COSE_Sign1 whose protected CWT_Claims header (label 15) carries `iss` (`opts.issuer`) and `sub` (`opts.subject`), with the payload media type declared via `opts.contentType` and extra CWT claims allowed by integer label (iss/sub cannot be overridden through `opts.claims`). `verifyStatement` verifies the signature through `b.cose.verify` (passing `opts.algorithms` as the mandatory allowlist), then requires a CWT_Claims header with both `iss` and `sub` — a bare COSE_Sign1 with no such binding is refused with `scitt/missing-cwt-claims` — and enforces `expectedIssuer` / `expectedSubject` when given. Returns `{ payload, issuer, subject, cwtClaims, alg, protectedHeaders, unprotectedHeaders }`. Because the identity binding lives in the integrity-protected header it is covered by the signature and cannot be substituted without detection. **Changed:** *`b.cose.sign` accepts `protectedHeaders` and a media-type-string `contentType`* — `opts.protectedHeaders` (a numeric-keyed object or Map) adds extra integrity-protected header parameters — the CWT_Claims map (label 15) is the SCITT case. Label 1 (alg) is reserved and managed via `opts.alg`; setting it through `protectedHeaders` is refused with `cose/reserved-header`. `opts.contentType` now accepts a media-type string (RFC 9052 §3.1 tstr form, e.g. `"application/spdx+json"`) in addition to a CoAP Content-Format uint; a string was previously dropped.
16
+
17
+ - v0.12.36 (2026-05-24) — **`b.cose.encrypt0` / `b.cose.decrypt0` — COSE_Encrypt0 single-recipient AEAD (RFC 9052 §5.2).** Completes the COSE family with encryption alongside the v0.12.33 signing: COSE_Encrypt0 is the single-recipient AEAD container where the recipient already holds the symmetric key (direct mode). The default algorithm is ChaCha20/Poly1305 (COSE alg 24) — AES-GCM stays opt-in, since hard-rule #2 forbids AES-GCM as a default. The Enc_structure (`["Encrypt0", protected, external_aad]`) is bound as the AEAD associated data so the algorithm + any external context are authenticated, and the authentication tag is appended to the ciphertext per COSE. Composes the in-tree `b.cbor` codec and `node:crypto` AEAD. **Added:** *`b.cose.encrypt0(plaintext, opts)` / `b.cose.decrypt0(coseEncrypt0, opts)`* — `encrypt0` produces a tagged COSE_Encrypt0 with `alg` in the protected header and a random 12-byte IV in the unprotected header (label 5); `alg` is `"ChaCha20-Poly1305"` (default), `"A256GCM"`, or `"A128GCM"`, with the key length enforced (32 / 16 bytes). `decrypt0` reads the algorithm from the protected header (must be in the required `opts.algorithms` allowlist), reconstructs the Enc_structure as the AEAD AAD, and returns `{ plaintext, alg, protectedHeaders, unprotectedHeaders }`; a wrong key, tampered ciphertext, or `external_aad` mismatch fails AEAD authentication and is refused with `cose/decrypt-failed`. `external_aad` binds request context into the tag.
18
+
19
+ - v0.12.35 (2026-05-24) — **`b.eat` — Entity Attestation Token (RFC 9711) over `b.cwt`.** An EAT is the token a Relying Party asks a device or software entity to produce to prove what it is and what state it is in — a freshness nonce, a Universal Entity ID, OEM / hardware identifiers, debug status, software measurements, and nested submodule attestations. `b.eat` is the RFC 9711 profile over the v0.12.34 `b.cwt`: it maps the EAT claim names to their IANA CWT claim-key integer labels and adds the attestation-specific verification on top of the CWT signature + time checks. The central control is the verifier-nonce binding: when the Relying Party supplies a fresh `expectedNonce`, the token's `eat_nonce` (claim 10) must match it (constant-time compare) — without it a captured attestation replays forever. `verify` also enforces a debug-status policy (`requireDebugDisabled` refuses an `enabled` or absent `dbgstat`) and pins the `eat_profile`. RFC 9711 is a finalized standard; signing follows `b.cwt` / `b.cose` (ES256/384/512 + EdDSA interoperable today, ML-DSA-87 PQC-forward). **Added:** *`b.eat.sign(claims, opts)` / `b.eat.verify(eat, opts)`* — `sign` maps EAT claim names (`nonce`, `ueid`, `oemid`, `hwmodel`, `dbgstat`, `eat_profile`, `swname`/`swversion`, `measurements`, `submods`, …) to their RFC 9711 integer labels and accepts the `dbgstat` enum by name (`disabled-since-boot` → 2); standard CWT claims (`iss` / `exp` / …) pass through. `verify` returns `{ claims, raw, alg, protectedHeaders }` with the labels mapped back to friendly names and `dbgstat` decoded to its enum name. Attestation enforcement: `expectedNonce` requires a matching `eat_nonce` (refused `eat/nonce-mismatch`, missing `eat/nonce-missing` — `eat_nonce` may be a single byte string or an array for multiple verifiers), `requireDebugDisabled` refuses a non-disabled `dbgstat` (`eat/debug-not-disabled`), and `expectedProfile` pins `eat_profile`. The signature, algorithm allowlist, and `exp`/`nbf` checks delegate to `b.cwt` / `b.cose`. · *`b.cwt.sign` accepts a `Map`* — `b.cwt.sign` now takes either a plain object (string keys, standard claims mapped by name) or a `Map`, which preserves integer claim keys verbatim — profiles like `b.eat` resolve their claim names to integer labels and pass them through without the keys being stringified. The plain-object path is unchanged.
20
+
21
+ - v0.12.34 (2026-05-24) — **`b.cwt` — CBOR Web Token (RFC 8392) sign / verify over `b.cose`.** A CWT is the CBOR-native counterpart to JWT — a signed claims set for constrained / IoT, FIDO attestation, and verifiable-credential contexts. `b.cwt` composes the v0.12.33 `b.cose` (COSE_Sign1 signature + mandatory algorithm allowlist) and v0.12.32 `b.cbor` (deterministic claims encoding) and layers the standard-claim handling on top: `sign` takes a friendly claims object, maps the standard claims to their RFC 8392 §3.1.1 integer labels (iss=1, sub=2, aud=3, exp=4, nbf=5, iat=6, cti=7), and signs; `verify` checks the COSE signature, decodes the claims, and enforces the time + identity claims — a passed `exp` (with clock-skew tolerance), a future `nbf`, and an `iss` / `aud` mismatch against the expected values are each refused. Signing algorithms follow `b.cose`: classical ES256/384/512 + EdDSA (final COSE ids, interoperable today) and ML-DSA-87 (PQC-forward). RFC 8392 is a finalized standard, so CWTs produced here interoperate with other COSE/CWT implementations. **Added:** *`b.cwt.sign(claims, opts)` / `b.cwt.verify(cwt, opts)`* — `sign` maps standard claim names to integer labels and keeps custom claims verbatim; `exp` / `nbf` / `iat` must be non-negative integer NumericDates. `opts.tagged` wraps the COSE_Sign1 in the CWT CBOR tag 61 (RFC 8392 §6); `verify` accepts tagged or bare input. `verify` returns `{ claims, raw, alg, protectedHeaders }` — `claims` is the friendly object (labels mapped back to names), `raw` the integer-keyed Map. Standard-claim enforcement: `exp` past `now + clockSkewSec` (default 60s) is refused with `cwt/expired`, `nbf` beyond `now - skew` with `cwt/not-yet-valid`, and `expectedIssuer` / `expectedAudience` mismatches with `cwt/issuer-mismatch` / `cwt/audience-mismatch` (aud may be a single value or an array). `opts.now` overrides the clock for testing. The signature itself is verified by `b.cose.verify`, so a tampered token fails there.
22
+
23
+ - v0.12.33 (2026-05-24) — **`b.cose` — COSE_Sign1 sign / verify (RFC 9052) over the in-tree CBOR codec.** COSE is the signed-statement substrate under SCITT, CWT, and C2PA — the CBOR-native counterpart to JWS. `b.cose` ships COSE_Sign1 signing and verification composing the v0.12.32 `b.cbor` codec for the deterministic Sig_structure encoding. It signs with the classical COSE algorithms that interoperate today — ES256 / ES384 / ES512 (ECDSA) and EdDSA (Ed25519), all with final IANA algorithm ids (RFC 9053) — and with ML-DSA-87 (FIPS 204) for PQC-forward deployments. Verification accepts the same set, so the framework both produces COSE other implementations read today and consumes third-party COSE. There is no classical default: the caller names the algorithm and supplies the key. **Added:** *`b.cose.sign(payload, opts)` / `b.cose.verify(coseSign1, opts)`* — `sign` produces a tagged COSE_Sign1 with `alg` in the integrity-protected header; `verify` returns `{ payload, alg, protectedHeaders, unprotectedHeaders }`. The Sig_structure (`["Signature1", protected, external_aad, payload]`) is deterministically CBOR-encoded; ECDSA signatures use the IEEE-P1363 fixed-width encoding COSE mandates (RFC 9053 §2.1), not ASN.1 DER. `external_aad` is bound into the signature. v1 is single-signer with an attached payload; detached payload, COSE_Sign (multi-signer), COSE_Mac0, and COSE_Encrypt are deferred-with-condition (operator demand). **Security:** *Bounded, alg-allowlisted, crit-checked verification* — `verify` decodes the COSE_Sign1 bytes AND the protected-header bstr through the bounded `b.cbor.decode` (depth + size caps, indefinite-length / tag / duplicate-key refusal). `opts.algorithms` is a required allowlist (no defaults — name the accepted algorithms). A `crit` header (label 2) listing a header label the verifier does not understand is refused (RFC 9052 §3.1 crit-bypass defense), as is a `crit` label absent from the protected header. The COSE algorithm switch refuses any unrecognized id at the default branch. · *ML-DSA-87 COSE algorithm id is a non-final draft* — ML-DSA-87 uses COSE algorithm id `-50`, a requested (non-final) IANA assignment from draft-ietf-cose-dilithium — an ML-DSA-87 COSE_Sign1 is not yet broadly interoperable and the id may change; it is pinned deliberately with the re-open condition being IANA finalization. SLH-DSA-SHAKE-256f has no registered COSE algorithm id at all and cannot be represented in COSE. The COSE_Sign1 mechanism and the classical algorithms are stable; ML-DSA-87 is the forward-looking opt-in.
24
+
11
25
  - v0.12.32 (2026-05-24) — **`b.cbor` — bounded, deterministic in-tree CBOR codec (RFC 8949).** CBOR is the binary serialization underneath COSE (RFC 9052), CWT, SCITT, and WebAuthn attestation — a foundational substrate the framework needs in-tree to build signed-statement primitives without a third-party parser. `b.cbor` is that codec, bounded by default like every parser the framework ships: a binary decoder is attack surface, so the defaults refuse the shapes a hostile encoder uses to exhaust memory or stack. The encoder emits Deterministically Encoded CBOR (RFC 8949 §4.2) — shortest-form heads, definite lengths, map keys sorted by encoded bytes, no indefinite-length items — so two semantically-equal values encode to byte-identical output, the property COSE signatures and SCITT receipts depend on. **Added:** *`b.cbor.encode(value, opts?)` / `b.cbor.decode(buffer, opts?)` / `b.cbor.Tag`* — `encode` produces deterministic CBOR from numbers (integers + float64), bigint (64-bit range), strings, `Buffer` / `Uint8Array`, arrays, `Map` or plain objects, `b.cbor.Tag`, and the simple values. `decode` returns the value with maps decoded to a `Map` (CBOR keys may be integers — COSE header labels are) and byte strings to `Buffer`. `b.cbor.Tag(tag, value)` carries a major-type-6 tagged item. `decode(buf, { requireDeterministic: true })` additionally asserts the input was itself canonically encoded (decode → re-encode → byte-compare), refusing a non-canonical re-encoding on a signature-verify path where it would be a malleability vector. **Security:** *Bounded-by-default decoder* — `maxDepth` (default 64, ceiling 256) caps nesting against stack exhaustion; `maxBytes` (default 16 MiB, ceiling 64 MiB) caps total input, and a declared string / array / map length exceeding the remaining bytes is refused before any allocation (no length-prefix memory bomb). Indefinite-length items (additional-info 31) are refused — a streaming-complexity / DoS vector forbidden by deterministic encoding. Reserved additional-info (28–30) is refused. Tags are refused unless allowlisted via `allowedTags` (a tag triggers semantic reprocessing — an un-vetted tag is a confused-deputy vector). Duplicate map keys (RFC 8949 §5.6) and trailing bytes after the data item are refused.
12
26
 
13
27
  - v0.12.31 (2026-05-24) — **`b.auth.jar.parse` — verify RFC 9101 JWT-Secured Authorization Requests (server side).** A plain OAuth authorization request carries its parameters in the URL query string, where a browser, proxy, or referer log can tamper with or leak them. RFC 9101 JAR packs those parameters into a JWT the client signs — the request object — so the authorization server can confirm they arrived exactly as sent. `b.auth.jar.parse(jar, opts)` is the server-side verifier and the request-side counterpart to the existing JARM response handling (`b.auth.oauth.parseJarmResponse`). It delegates the signature check to `b.auth.jwt.verifyExternal` — which already enforces a mandatory `algorithms` allowlist and refuses the alg-confusion (`alg: "none"`, HMAC-vs-RSA) and JWE-on-a-JWS-verifier shapes against a JWKS public-key trust source — then pins `iss` and the `client_id` claim to the expected client, pins `aud` to this server's issuer identifier, refuses a nested `request` / `request_uri` (RFC 9101 §6.3 recursion / confused-deputy vector), and returns the authorization parameters with the JWT envelope claims stripped. **Added:** *`b.auth.jar.parse(jar, opts)` — request-object verification* — `opts.clientId` (the expected client — pins `iss` + the `client_id` claim), `opts.audience` (this server's issuer identifier — pins `aud`), `opts.algorithms` (required signature allowlist — no defaults, the alg-confusion defense), and one of `opts.jwks` / `opts.jwksUri` / `opts.keyResolver` (the client's verification key). Returns `{ params, claims }` where `params` is the authorization parameters (`response_type`, `redirect_uri`, `scope`, `state`, `nonce`, …) with the JWT envelope claims (`iss`, `aud`, `exp`, `iat`, `nbf`, `jti`) removed. A request object whose `client_id` claim disagrees with `opts.clientId`, or that nests a `request` / `request_uri`, is refused. Emitting a request object (the client side) is deferred-with-condition: it requires signing with the client's key under a classical JWS algorithm, and the framework's own JWT signer is PQC-only for the tokens it issues — a PQC-signed request object would not interoperate with a standard authorization server; client-side emission re-opens when a classical JWS signer lands or operators surface the need. Until then clients sign request objects with their existing JOSE tooling.
@@ -126,6 +126,12 @@ The framework bundles the surface a typical Node app reaches for. Every primitiv
126
126
  - **JSON / SQL / schema** — `b.safeJson` (with `maxKeys` cap defending CVE-2026-21717 V8 HashDoS), `b.safeBuffer`, `b.safeSql`, `b.safeSchema`
127
127
  - **URL + path** — `b.safeUrl` (IDN mixed-script / homograph refuse); `b.safeJsonPath` (refuses filter `?(...)`, deep-scan `$..`, script-shape `(@.x)` for safe Postgres JSONB ops)
128
128
  - **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
129
+ - **COSE signing + encryption** — `b.cose` COSE_Sign1 sign/verify + COSE_Encrypt0 (RFC 9052) over `b.cbor`: 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; single-recipient AEAD (ChaCha20/Poly1305 default, AES-GCM opt-in) with Enc_structure-bound AAD; the signed-statement substrate under SCITT / CWT / C2PA
130
+ - **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
131
+ - **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
132
+ - **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
133
+ - **Trusted timestamping** — `b.tsa` RFC 3161 timestamp client: `buildRequest` a TimeStampReq, `parseResponse`, and `verifyToken` against your data — the message imprint, sent nonce, critical/sole `id-kp-timeStamping` EKU, and CMS signature are all checked, with optional certificate-chain verification. Timestamp a release artifact, audit checkpoint, or signed statement against any RFC 3161 TSA. Composes `b.cms` + the in-tree ASN.1 DER codec
134
+ - **Verifiable Credentials** — `b.vc` W3C Verifiable Credentials Data Model 2.0 (VC-JOSE-COSE): `issue` / `verify` a signed credential as a compact JWS (`vc+jwt`, ES256/384/512 + EdDSA) or a COSE_Sign1 (`vc+cose`, + ML-DSA-87) over `b.cose`. VCDM structural + `validFrom`/`validUntil` checks; the JOSE `none` algorithm is always refused. The W3C model, distinct from the IETF SD-JWT VC at `b.auth.sdJwtVc`
129
135
  - **Document parsers** — `b.parsers` (XML / TOML / YAML / .env); `b.config` (schema-validated env)
130
136
  - **File-type detection** — `b.fileType` magic-byte content classification with deny-on-upload categories (image / document / archive / executable / etc.)
131
137
  ### Content-safety gates
@@ -376,6 +376,10 @@ This is the minimum-viable security posture for a production deployment. The fra
376
376
  - [ ] For idempotency-key middleware on multi-process fleets — use `b.middleware.idempotencyKey.dbStore({ db: b.db })` instead of `memoryStore`. As of v0.9.15 the dbStore defaults to `hashKeys: true` (operator-supplied keys are sha3-512 namespace-hashed before insert/lookup so the DB never sees raw keys that might carry PII — order numbers / emails / vendor prefixes) and `seal: true` (cached response `headers` + `body` are sealed via `b.cryptoField.sealRow` AEAD envelope when vault is initialized so a DB dump leaks neither). Forensic columns (`status_code` / `fingerprint` / `expires_at`) stay plaintext-queryable without unsealing. Opt-out via `{ hashKeys: false, seal: false }` only with a documented justification
377
377
  - [ ] For long-running daemons exposing live metrics — use `b.metrics.snapshot.startWriter({ path, intervalMs, fields })` to flush an atomic JSON snapshot to disk; let a CLI/sidecar consume it via `b.metrics.snapshot.read(path)` + `b.metrics.snapshot.render(snap, { format: "prometheus" | "text" })`. Avoids opening an HTTP port for scrape access. Snapshot read uses `b.safeJson.parse` with a 4 MiB ceiling so a hostile writer with disk-write access can't OOM the reader
378
378
  - [ ] For decoding CBOR from untrusted sources (COSE / CWT / WebAuthn attestation objects, IoT payloads): use `b.cbor.decode(buffer, opts)` — bounded by default (depth + total-size caps, indefinite-length + reserved-info refusal), never a raw streaming parser. Allowlist only the tags you process via `allowedTags` (an un-vetted tag triggers semantic reprocessing — a confused-deputy vector), and on a signature-verify path pass `requireDeterministic: true` so a non-canonical re-encoding can't slip a malleable representation past the verifier
379
+ - [ ] For verifying COSE_Sign1 (RFC 9052) signed statements (SCITT receipts, CWT, C2PA manifests): use `b.cose.verify(coseSign1, { algorithms, publicKey })` — `algorithms` is a required allowlist (no defaults, the alg-confusion defense), the COSE bytes + protected header decode through the bounded `b.cbor`, and a `crit` header naming a label the verifier doesn't understand is refused (§3.1 crit-bypass). Bind request context with `externalAad`. ML-DSA-87's COSE id is a non-final draft — prefer the classical ES256 / EdDSA ids for interoperable signing today
380
+ - [ ] For COSE_Encrypt0 (RFC 9052 §5.2 single-recipient AEAD): use `b.cose.encrypt0` / `b.cose.decrypt0` — the default is ChaCha20/Poly1305 (AES-GCM is opt-in), the IV is generated fresh per call (never reuse an IV with the same key), and `decrypt0` requires an `algorithms` allowlist + reconstructs the Enc_structure as AAD so a wrong key / tampered ciphertext / AAD mismatch fails authentication. Pass `externalAad` to bind the ciphertext to its context
381
+ - [ ] For CBOR Web Tokens (RFC 8392 — constrained / IoT / FIDO auth): verify with `b.cwt.verify(cwt, { algorithms, publicKey, expectedIssuer, expectedAudience })` — it enforces the COSE alg allowlist (via `b.cose.verify`), refuses an expired `exp` or future `nbf` (with a bounded `clockSkewSec`, default 60s), and refuses an `iss` / `aud` mismatch. Always pass `expectedIssuer` + `expectedAudience` for tokens you consume so a token minted for a different service or issuer can't be replayed against yours
382
+ - [ ] For device / software attestation (RFC 9711 EAT): send the attester a fresh random nonce and verify the returned token with `b.eat.verify(eat, { algorithms, publicKey, expectedNonce, requireDebugDisabled: true })` — the `expectedNonce` binding is the freshness / anti-replay control (without it a captured attestation replays forever), and `requireDebugDisabled` refuses a device whose `dbgstat` is enabled or absent. Pin `expectedProfile` to the EAT profile you understand so a token built to a different profile's semantics isn't misinterpreted
379
383
  - [ ] For install-pipeline contexts that run BEFORE the framework is installed (Dockerfile build stages, `install.sh`, `update.sh`, SEA bundle verification) — use `b.selfUpdate.standaloneVerifier` (since v0.9.13). It's a zero-dep verifier (only `node:crypto` + `node:fs`) for ECDSA P-384 / Ed25519 / ML-DSA-87 signatures. Operators physically copy the file via `cp "$(node -p "require('@blamejs/core').selfUpdate.standaloneVerifier.path")" install/standalone-verifier.js` into their install pipeline alongside an operator-owned pubkey
380
384
  - [ ] For daemons that rotate TLS posture without restarting (pinset reload / certificate refresh / `C.TLS_GROUP_PREFERENCE` updates) — call `b.pqcAgent.reload()` after the posture change so the next `b.pqcAgent.agent` access rebuilds against current TLS state. Existing in-flight sockets complete naturally; idle keep-alive sockets are torn down
381
385
  - [ ] For SBOM regeneration / vendor-data integrity sweeps / release-asset bundling — use `b.crypto.hashFilesParallel(filePaths, { algorithms, concurrency, onProgress })` to hash N files in parallel in a single-pass per file. Operator-tunable concurrency cap (default `min(8, paths.length)`, range 1..256) + tunable algorithms list (default `["sha256", "sha3-512"]` for PQC-first + legacy compat). Returns rows in input order
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 1,
3
- "frameworkVersion": "0.12.32",
4
- "createdAt": "2026-05-24T19:44:18.478Z",
3
+ "frameworkVersion": "0.12.39",
4
+ "createdAt": "2026-05-25T02:42:46.281Z",
5
5
  "exports": {
6
6
  "a2a": {
7
7
  "type": "object",
@@ -13452,6 +13452,81 @@
13452
13452
  }
13453
13453
  }
13454
13454
  },
13455
+ "cose": {
13456
+ "type": "object",
13457
+ "members": {
13458
+ "AEAD_ALGORITHMS": {
13459
+ "type": "object",
13460
+ "members": {
13461
+ "A128GCM": {
13462
+ "type": "primitive",
13463
+ "valueType": "number"
13464
+ },
13465
+ "A256GCM": {
13466
+ "type": "primitive",
13467
+ "valueType": "number"
13468
+ },
13469
+ "ChaCha20-Poly1305": {
13470
+ "type": "primitive",
13471
+ "valueType": "number"
13472
+ }
13473
+ }
13474
+ },
13475
+ "ALGORITHMS": {
13476
+ "type": "object",
13477
+ "members": {
13478
+ "ES256": {
13479
+ "type": "primitive",
13480
+ "valueType": "number"
13481
+ },
13482
+ "ES384": {
13483
+ "type": "primitive",
13484
+ "valueType": "number"
13485
+ },
13486
+ "ES512": {
13487
+ "type": "primitive",
13488
+ "valueType": "number"
13489
+ },
13490
+ "EdDSA": {
13491
+ "type": "primitive",
13492
+ "valueType": "number"
13493
+ },
13494
+ "ML-DSA-87": {
13495
+ "type": "primitive",
13496
+ "valueType": "number"
13497
+ }
13498
+ }
13499
+ },
13500
+ "COSE_ENCRYPT0_TAG": {
13501
+ "type": "primitive",
13502
+ "valueType": "number"
13503
+ },
13504
+ "COSE_SIGN1_TAG": {
13505
+ "type": "primitive",
13506
+ "valueType": "number"
13507
+ },
13508
+ "CoseError": {
13509
+ "type": "function",
13510
+ "arity": 4
13511
+ },
13512
+ "decrypt0": {
13513
+ "type": "function",
13514
+ "arity": 2
13515
+ },
13516
+ "encrypt0": {
13517
+ "type": "function",
13518
+ "arity": 2
13519
+ },
13520
+ "sign": {
13521
+ "type": "function",
13522
+ "arity": 2
13523
+ },
13524
+ "verify": {
13525
+ "type": "function",
13526
+ "arity": 2
13527
+ }
13528
+ }
13529
+ },
13455
13530
  "cra": {
13456
13531
  "type": "object",
13457
13532
  "members": {
@@ -13949,6 +14024,56 @@
13949
14024
  }
13950
14025
  }
13951
14026
  },
14027
+ "cwt": {
14028
+ "type": "object",
14029
+ "members": {
14030
+ "CLAIM_LABELS": {
14031
+ "type": "object",
14032
+ "members": {
14033
+ "aud": {
14034
+ "type": "primitive",
14035
+ "valueType": "number"
14036
+ },
14037
+ "cti": {
14038
+ "type": "primitive",
14039
+ "valueType": "number"
14040
+ },
14041
+ "exp": {
14042
+ "type": "primitive",
14043
+ "valueType": "number"
14044
+ },
14045
+ "iat": {
14046
+ "type": "primitive",
14047
+ "valueType": "number"
14048
+ },
14049
+ "iss": {
14050
+ "type": "primitive",
14051
+ "valueType": "number"
14052
+ },
14053
+ "nbf": {
14054
+ "type": "primitive",
14055
+ "valueType": "number"
14056
+ },
14057
+ "sub": {
14058
+ "type": "primitive",
14059
+ "valueType": "number"
14060
+ }
14061
+ }
14062
+ },
14063
+ "CwtError": {
14064
+ "type": "function",
14065
+ "arity": 4
14066
+ },
14067
+ "sign": {
14068
+ "type": "function",
14069
+ "arity": 2
14070
+ },
14071
+ "verify": {
14072
+ "type": "function",
14073
+ "arity": 2
14074
+ }
14075
+ }
14076
+ },
13952
14077
  "daemon": {
13953
14078
  "type": "object",
13954
14079
  "members": {
@@ -14676,6 +14801,117 @@
14676
14801
  }
14677
14802
  }
14678
14803
  },
14804
+ "eat": {
14805
+ "type": "object",
14806
+ "members": {
14807
+ "CLAIM_LABELS": {
14808
+ "type": "object",
14809
+ "members": {
14810
+ "dbgstat": {
14811
+ "type": "primitive",
14812
+ "valueType": "number"
14813
+ },
14814
+ "eat_profile": {
14815
+ "type": "primitive",
14816
+ "valueType": "number"
14817
+ },
14818
+ "hwmodel": {
14819
+ "type": "primitive",
14820
+ "valueType": "number"
14821
+ },
14822
+ "hwversion": {
14823
+ "type": "primitive",
14824
+ "valueType": "number"
14825
+ },
14826
+ "location": {
14827
+ "type": "primitive",
14828
+ "valueType": "number"
14829
+ },
14830
+ "manifests": {
14831
+ "type": "primitive",
14832
+ "valueType": "number"
14833
+ },
14834
+ "measurements": {
14835
+ "type": "primitive",
14836
+ "valueType": "number"
14837
+ },
14838
+ "nonce": {
14839
+ "type": "primitive",
14840
+ "valueType": "number"
14841
+ },
14842
+ "oemboot": {
14843
+ "type": "primitive",
14844
+ "valueType": "number"
14845
+ },
14846
+ "oemid": {
14847
+ "type": "primitive",
14848
+ "valueType": "number"
14849
+ },
14850
+ "submods": {
14851
+ "type": "primitive",
14852
+ "valueType": "number"
14853
+ },
14854
+ "sueids": {
14855
+ "type": "primitive",
14856
+ "valueType": "number"
14857
+ },
14858
+ "swname": {
14859
+ "type": "primitive",
14860
+ "valueType": "number"
14861
+ },
14862
+ "swversion": {
14863
+ "type": "primitive",
14864
+ "valueType": "number"
14865
+ },
14866
+ "ueid": {
14867
+ "type": "primitive",
14868
+ "valueType": "number"
14869
+ },
14870
+ "uptime": {
14871
+ "type": "primitive",
14872
+ "valueType": "number"
14873
+ }
14874
+ }
14875
+ },
14876
+ "DBGSTAT": {
14877
+ "type": "object",
14878
+ "members": {
14879
+ "disabled": {
14880
+ "type": "primitive",
14881
+ "valueType": "number"
14882
+ },
14883
+ "disabled-fully-and-permanently": {
14884
+ "type": "primitive",
14885
+ "valueType": "number"
14886
+ },
14887
+ "disabled-permanently": {
14888
+ "type": "primitive",
14889
+ "valueType": "number"
14890
+ },
14891
+ "disabled-since-boot": {
14892
+ "type": "primitive",
14893
+ "valueType": "number"
14894
+ },
14895
+ "enabled": {
14896
+ "type": "primitive",
14897
+ "valueType": "number"
14898
+ }
14899
+ }
14900
+ },
14901
+ "EatError": {
14902
+ "type": "function",
14903
+ "arity": 4
14904
+ },
14905
+ "sign": {
14906
+ "type": "function",
14907
+ "arity": 2
14908
+ },
14909
+ "verify": {
14910
+ "type": "function",
14911
+ "arity": 2
14912
+ }
14913
+ }
14914
+ },
14679
14915
  "errorPage": {
14680
14916
  "type": "object",
14681
14917
  "members": {
@@ -47563,6 +47799,27 @@
47563
47799
  }
47564
47800
  }
47565
47801
  },
47802
+ "scitt": {
47803
+ "type": "object",
47804
+ "members": {
47805
+ "CWT_CLAIMS_LABEL": {
47806
+ "type": "primitive",
47807
+ "valueType": "number"
47808
+ },
47809
+ "ScittError": {
47810
+ "type": "function",
47811
+ "arity": 4
47812
+ },
47813
+ "signStatement": {
47814
+ "type": "function",
47815
+ "arity": 2
47816
+ },
47817
+ "verifyStatement": {
47818
+ "type": "function",
47819
+ "arity": 2
47820
+ }
47821
+ }
47822
+ },
47566
47823
  "sdNotify": {
47567
47824
  "type": "object",
47568
47825
  "members": {
@@ -48381,6 +48638,97 @@
48381
48638
  }
48382
48639
  }
48383
48640
  },
48641
+ "tsa": {
48642
+ "type": "object",
48643
+ "members": {
48644
+ "IMPRINT_HASHES": {
48645
+ "type": "object",
48646
+ "members": {
48647
+ "SHA-256": {
48648
+ "type": "object",
48649
+ "members": {
48650
+ "nodeHash": {
48651
+ "type": "primitive",
48652
+ "valueType": "string"
48653
+ },
48654
+ "oid": {
48655
+ "type": "primitive",
48656
+ "valueType": "string"
48657
+ }
48658
+ }
48659
+ },
48660
+ "SHA-384": {
48661
+ "type": "object",
48662
+ "members": {
48663
+ "nodeHash": {
48664
+ "type": "primitive",
48665
+ "valueType": "string"
48666
+ },
48667
+ "oid": {
48668
+ "type": "primitive",
48669
+ "valueType": "string"
48670
+ }
48671
+ }
48672
+ },
48673
+ "SHA-512": {
48674
+ "type": "object",
48675
+ "members": {
48676
+ "nodeHash": {
48677
+ "type": "primitive",
48678
+ "valueType": "string"
48679
+ },
48680
+ "oid": {
48681
+ "type": "primitive",
48682
+ "valueType": "string"
48683
+ }
48684
+ }
48685
+ },
48686
+ "SHA3-256": {
48687
+ "type": "object",
48688
+ "members": {
48689
+ "nodeHash": {
48690
+ "type": "primitive",
48691
+ "valueType": "string"
48692
+ },
48693
+ "oid": {
48694
+ "type": "primitive",
48695
+ "valueType": "string"
48696
+ }
48697
+ }
48698
+ },
48699
+ "SHA3-512": {
48700
+ "type": "object",
48701
+ "members": {
48702
+ "nodeHash": {
48703
+ "type": "primitive",
48704
+ "valueType": "string"
48705
+ },
48706
+ "oid": {
48707
+ "type": "primitive",
48708
+ "valueType": "string"
48709
+ }
48710
+ }
48711
+ }
48712
+ }
48713
+ },
48714
+ "TsaError": {
48715
+ "type": "function",
48716
+ "arity": 4
48717
+ },
48718
+ "buildRequest": {
48719
+ "type": "function",
48720
+ "arity": 2
48721
+ },
48722
+ "parseResponse": {
48723
+ "type": "function",
48724
+ "arity": 1
48725
+ },
48726
+ "verifyToken": {
48727
+ "type": "function",
48728
+ "arity": 2
48729
+ }
48730
+ }
48731
+ },
48384
48732
  "uuid": {
48385
48733
  "type": "object",
48386
48734
  "members": {
@@ -48685,6 +49033,80 @@
48685
49033
  }
48686
49034
  }
48687
49035
  },
49036
+ "vc": {
49037
+ "type": "object",
49038
+ "members": {
49039
+ "JOSE_ALGS": {
49040
+ "type": "object",
49041
+ "members": {
49042
+ "ES256": {
49043
+ "type": "object",
49044
+ "members": {
49045
+ "dsaEncoding": {
49046
+ "type": "primitive",
49047
+ "valueType": "string"
49048
+ },
49049
+ "nodeHash": {
49050
+ "type": "primitive",
49051
+ "valueType": "string"
49052
+ }
49053
+ }
49054
+ },
49055
+ "ES384": {
49056
+ "type": "object",
49057
+ "members": {
49058
+ "dsaEncoding": {
49059
+ "type": "primitive",
49060
+ "valueType": "string"
49061
+ },
49062
+ "nodeHash": {
49063
+ "type": "primitive",
49064
+ "valueType": "string"
49065
+ }
49066
+ }
49067
+ },
49068
+ "ES512": {
49069
+ "type": "object",
49070
+ "members": {
49071
+ "dsaEncoding": {
49072
+ "type": "primitive",
49073
+ "valueType": "string"
49074
+ },
49075
+ "nodeHash": {
49076
+ "type": "primitive",
49077
+ "valueType": "string"
49078
+ }
49079
+ }
49080
+ },
49081
+ "EdDSA": {
49082
+ "type": "object",
49083
+ "members": {
49084
+ "nodeHash": {
49085
+ "type": "primitive",
49086
+ "valueType": "null"
49087
+ }
49088
+ }
49089
+ }
49090
+ }
49091
+ },
49092
+ "VCDM_V2_CONTEXT": {
49093
+ "type": "primitive",
49094
+ "valueType": "string"
49095
+ },
49096
+ "VcError": {
49097
+ "type": "function",
49098
+ "arity": 4
49099
+ },
49100
+ "issue": {
49101
+ "type": "function",
49102
+ "arity": 2
49103
+ },
49104
+ "verify": {
49105
+ "type": "function",
49106
+ "arity": 2
49107
+ }
49108
+ }
49109
+ },
48688
49110
  "vendorData": {
48689
49111
  "type": "object",
48690
49112
  "members": {
@@ -456,6 +456,12 @@ module.exports = {
456
456
  // the codepoint-stability contract.
457
457
  jose: { jwe: { experimental: require("./lib/jose-jwe-experimental") } },
458
458
  cbor: require("./lib/cbor"),
459
+ cose: require("./lib/cose"),
460
+ cwt: require("./lib/cwt"),
461
+ eat: require("./lib/eat"),
462
+ scitt: require("./lib/scitt"),
463
+ tsa: require("./lib/tsa"),
464
+ vc: require("./lib/vc"),
459
465
  queue: queue,
460
466
  logStream: logStream,
461
467
  redact: redact,