@blamejs/core 0.8.51 → 0.8.57
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 +6 -0
- package/index.js +8 -0
- package/lib/audit.js +4 -0
- package/lib/auth/fido-mds3.js +624 -0
- package/lib/auth/passkey.js +214 -2
- package/lib/auth-bot-challenge.js +1 -1
- package/lib/credential-hash.js +2 -2
- package/lib/framework-error.js +55 -0
- package/lib/guard-cidr.js +2 -1
- package/lib/guard-jwt.js +2 -2
- package/lib/guard-oauth.js +2 -2
- package/lib/http-client-cache.js +916 -0
- package/lib/http-client.js +242 -0
- package/lib/local-db-thin.js +8 -7
- package/lib/mail-arf.js +343 -0
- package/lib/mail-auth.js +265 -40
- package/lib/mail-bimi.js +948 -33
- package/lib/mail-bounce.js +386 -4
- package/lib/mail-mdn.js +424 -0
- package/lib/mail-unsubscribe.js +265 -25
- package/lib/mail.js +403 -21
- package/lib/middleware/bearer-auth.js +1 -1
- package/lib/middleware/clear-site-data.js +122 -0
- package/lib/middleware/dpop.js +1 -1
- package/lib/middleware/index.js +9 -0
- package/lib/middleware/nel.js +214 -0
- package/lib/middleware/security-headers.js +56 -4
- package/lib/middleware/speculation-rules.js +323 -0
- package/lib/mime-parse.js +198 -0
- package/lib/network-dns.js +890 -27
- package/lib/network-tls.js +745 -0
- package/lib/object-store/sigv4.js +54 -0
- package/lib/public-suffix.js +414 -0
- package/lib/safe-buffer.js +7 -0
- package/lib/safe-json.js +1 -1
- package/lib/static.js +120 -0
- package/lib/storage.js +11 -0
- package/lib/vendor/MANIFEST.json +33 -0
- package/lib/vendor/bimi-trust-anchors.pem +33 -0
- package/lib/vendor/public-suffix-list.dat +16376 -0
- package/package.json +1 -1
- package/sbom.cyclonedx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,12 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.8.x
|
|
10
10
|
|
|
11
|
+
- v0.8.57 (2026-05-09) — CI green-up for v0.8.56. The v0.8.56 npm-publish workflow's smoke gate passed but the `prepack-guard` script (`scripts/check-pack-against-gitignore.js`) rejected the tarball: it ran `git check-ignore -v` against every packed path and treated EVERY matching gitignore line as "ignored", including `!`-prefixed negation rules. The newly-tracked `lib/vendor/bimi-trust-anchors.pem` matches the `!lib/vendor/*.pem` negation rule that v0.8.54 added, but the script flagged it as "gitignored in tarball" and exited 1. Fix: filter out lines whose matching pattern starts with `!` — those are negation rules indicating the file is NOT actually ignored. No primitive surface change versus v0.8.56.
|
|
12
|
+
- v0.8.56 (2026-05-09) — CI green-up for v0.8.55. macOS smoke runner failed `watcher.test.js: surface onChange for non-ignored file`; the test bumped from 80ms→300ms in v0.8.52, but macOS `fs.watch` event delivery under SMOKE_PARALLEL=64 + CI runner contention can still exceed 300ms. Bumped all four delay sites to 1500ms. Linux/Windows continue to pass on the first event-loop turn; the longer budget only matters when macOS is contended. No primitive surface change versus v0.8.55.
|
|
13
|
+
- v0.8.55 (2026-05-09) — CI green-up for v0.8.54. The v0.8.54 npm-publish hit `rate-limit-cluster.test.js: cluster: 4th request blocked with 429` failing under CI contention. The test's `_waitMicrotasks(3)` helper chained 3 `setImmediate` ticks between `fire()` calls, and the cluster-backend's async `take()` against the DB hadn't finished bumping the counter yet — the 4th `fire()` read a stale count, looked like a pass, and the assertion failed. Bumped to 20 ticks (default + every call site). Linux/Alpine container runners pass on the first attempt; the budget only matters under SMOKE_PARALLEL=64 contention. No primitive surface change versus v0.8.54.
|
|
14
|
+
- v0.8.54 (2026-05-09) — CI green-up for v0.8.53. The v0.8.53 push tripped `configDrift.verifyVendorIntegrity` because `lib/vendor/bimi-trust-anchors.pem` was excluded by the global `*.pem` rule in `.gitignore` (designed to block accidental commit of operator-private keys), so the file landed in MANIFEST.json with a SHA-256 hash but never reached the git tree. CI checked out a tree without the PEM, the integrity gate failed, and npm-publish never ran. `.gitignore` now adds an explicit `!lib/vendor/*.pem` / `!lib/vendor/*.crt` exception with a comment documenting why (vendored cert bundles are public framework assets, not operator-private material). The PEM is now tracked. No primitive surface change versus v0.8.53.
|
|
15
|
+
- v0.8.53 (2026-05-09) — substantial additive surface from a 9-batch parallel build closing two audit clusters in one patch. **Browser hardening**: `b.middleware.clearSiteData` (RFC 9527 logout-side state wipe — cookies / storage / cache / executionContexts / clientHints + wildcard); `b.middleware.nel` (W3C Network Error Logging emitter — emits `NEL` + `Report-To` headers, https-only collector, CR/LF/NUL injection refusal); `b.middleware.speculationRules` (W3C Speculation Rules emitter, header form by default + `inline: true` for inline `<script type="speculationrules">`); `Document-Policy` header default in `b.middleware.securityHeaders` (`document-write=?0, unsized-media=?0, oversized-images=?0`) plus operator override; CSP3 `fenced-frame-src 'none'` baked into `DEFAULT_CSP`; `Accept-CH` + `Critical-CH` UA-CH retry handshake opts; RFC 9651 Permissions-Policy structured-fields validation at config-time; `b.static` `forceAttachmentForNonText: true` opt — every served file outside the safe-render allowlist gets `Content-Disposition: attachment` + `nosniff` (defense in depth against stored-XSS via uploaded HTML/JS). **WebAuthn / FIDO**: WebAuthn L3 §6.1.3 BE/BS flag surface (`backupEligible` + `backupState` on verify*returns); `b.auth.passkey.extensions.{prf, largeBlob, credBlob}` extension-helper builders; `b.auth.passkey.conditionalAuthOptions` for `mediation: "conditional"` autofill; new `b.auth.fidoMds3` AAGUID metadata verifier — JWS-signed BLOB fetch + cert-chain validation against the FIDO Alliance MDS3 root, AAGUID lookup, REVOKED / USER_KEY_PHYSICAL_COMPROMISE / USER_KEY_REMOTE_COMPROMISE refusal, in-memory cache TTL = `nextUpdate - now`. **Public Suffix List substrate**: new `b.publicSuffix.{publicSuffix, organizationalDomain, isPublicSuffix, lookupSource}` with vendored Mozilla PSL data (10,207 rules) — exact-match > exception > wildcard > implicit `*` per the canonical algorithm, IDNA Punycode normalisation; consumed by the DMARCbis + BIMI work below. **Email auth**: DMARCbis `psd=` / `np=` / org-domain discovery via PSL in `lib/mail-auth.js`; RFC 9091 BIMI VMC + CMC chain validation in `b.mail.bimi.fetchAndVerifyMark` (httpClient-fetched cert, cert-path validation against vendored BIMI Trust Anchor roots, `subjectAltName` URI match, RFC 3709 logotype extension parsing for the embedded SVG, BIMI policy OID gate); Tiny-PS SVG profile validator (`b.mail.bimi.validateTinyPsSvg`) refusing `<script>` / `<style>` / `<foreignObject>` / `<animate*>` / external refs / >32 KiB; RFC 8617 ARC trust-eval (`arcEvaluate` returns `{ trust, trustedHops, finalAr, breakAt }`); RFC 5965 ARF abuse-feedback ingestion (new `b.mailArf.parse`); RFC 8601 iprev / FCrDNS verifier (`b.mail.iprev.verify` exposed via `b.mail.reverseDns`). **Email transport**: RFC 3030 BDAT / CHUNKING / BINARYMIME framing in `b.mail.send` (default chunk size 256 KiB, BODY=BINARYMIME / 8BITMIME negotiation, refuse-on-binary-without-peer-support); RFC 1870 SIZE pre-MAIL-FROM cap; IPv6 submission + AAAA preference auto-detect (`preferFamily: 4|6|"any"`); generic RFC 3461/3464 DSN parser + generator in `b.mailBounce.dsn.{parse,build}` (multipart/report message/delivery-status, RFC 6533 SMTPUTF8 EAI-aware); RFC 3798/8098 MDN builder + parser (`b.mailMdn.{build,parse}` — refuses auto-generation when inbound message asserts `important=required`); RFC 2369 / 2919 List-Help / List-Owner / List-Archive / List-ID bundle in `b.mail.unsubscribe.buildAllListHeaders`. **DNS**: RFC 9460 SVCB / HTTPS RR query+parse (`b.network.dns.{querySvcb, queryHttps}` — AliasMode + ServiceMode, full SvcParam vocabulary including `ech` / `alpn` / `mandatory` / `dohpath` / `ipv4hint` / `ipv6hint`); RFC 7858 DoT first-class transport (`transport: "dot"` opt + connection pool); RFC 9462 DDR (`b.network.dns.discoverEncrypted` queries `_dns.resolver.arpa`); RFC 9463 DNR (`b.network.dns.useDesignatedResolvers` operator-side resolver advertisement); generic `b.network.dns.resolve(name, type, opts)` dispatcher; `b.network.dns.reverse(ip)` PTR helper. RFC 9250 DoQ explicitly NOT shipped — Node QUIC is experimental; documented deferral in `lib/network-dns.js`. **TLS**: ECH outbound from SVCB (`b.network.tls.connectWithEch` queries HTTPS RR, parses `ech=` SvcParam per draft-ietf-tls-esni-22 §4 ECHConfigList wire format, attaches to `tls.connect({ ech })` with feature-detect graceful degrade); RFC 9525 strict PKIX server identity verification (`b.network.tls.checkServerIdentity9525` — SAN dNSName required when present, CN-fallback refused, wildcard one-label limit, IP SAN matching). **HTTP cache**: full RFC 9111 outbound HTTP cache primitive (`b.httpClient.cache.create({ store, sharedCache, defaultMaxStale, revalidateInBackground })` + `b.httpClient.cache.memoryStore({ maxBytes, maxEntries, evictionPolicy })`) — §3 storage decision (status allowlist + Cache-Control directives + `Vary` keying), §4.2 freshness (s-maxage > max-age > Expires-Date > heuristic 10% capped at 24h), §4.3 conditional revalidation (`If-None-Match` + `If-Modified-Since`), §5 304 merge, RFC 5861 `stale-while-revalidate` + `stale-if-error`; `Age` + `X-Blamejs-Cache: HIT|MISS|STALE|REVALIDATED` response headers; `httpclient.cache.{hit,miss,stale,revalidated,evicted}` audit emissions. **Object store**: `responseHeaders` opt on SigV4 `presignedDownloadUrl` (`{ contentDisposition?, contentType?, contentLanguage?, contentEncoding?, cacheControl?, expires? }`) — adds the S3 response-* override query params to the signed URL so a presigned GET overrides Content-Disposition / Content-Type / etc. on the wire regardless of how the object was stored; SigV4 signing math is identical (params land in canonicalQueryString before hashing). Verified end-to-end against live MinIO via `scripts/test-integration.js object-store-sigv4` (HTTP + TLS variants, server-side header honoring confirmed). **Wiki**: source-driven validators now handle nested namespaces (`b.middleware.clearSiteData`, `b.mail.bimi`, `b.httpClient.cache`) — `validate-source-comment-blocks.js` + `validate-site-coverage.js` index every prefix, `auto-site-entries.js` flattens dotted slugs to kebab-case for routability, `page-generator.js` uses longest-prefix match to group primitives under nested-namespace pages. Per-primitive Layer 0 tests for `clear-site-data`, `nel`, `speculation-rules`, `security-headers` (new opts), `static` (Content-Disposition opt), `passkey` (BE/BS + extensions + conditional UI), `fido-mds3`, `mail-arf`, `mail-mdn`, `mail-bimi`, `network-dns` (SVCB/DoT/DDR/DNR), `network-tls` (ECH + RFC 9525), `http-client-cache`, `public-suffix`. Live integration test for SigV4 `responseHeaders` round-trip. CLAUDE.md release workflow now documents the live integration step (`scripts/test-integration.js` + `NODE_EXTRA_CA_CERTS`). +13k LoC across 50+ files.
|
|
16
|
+
- v0.8.52 (2026-05-09) — Cross-platform smoke flake fixes. Two pre-existing platform fragilities surfaced under v0.8.51 CI runner contention: (a) `lib/local-db-thin.js` corrupt-file recovery rename retried 5×50ms (250ms total) before giving up — Windows holds a sqlite file lock several hundred ms after `DatabaseSync.close()` returns under load, and CI runner pressure pushed the unlock past the budget. The retry window is now 20×100ms (2s total); Linux/macOS still land on the first attempt. (b) `test/layer-0-primitives/watcher.test.js` waited 80ms after writing files before asserting `fs.watch` events landed; macOS delivers events later than Linux/Windows under contention. The test wait is now 300ms in all four delay sites. No primitive surface change versus v0.8.51.
|
|
11
17
|
- v0.8.51 (2026-05-09) — CI green-up follow-on for v0.8.50. Two CI gates still failed on v0.8.50: (a) the wiki @module/@primitive validator step couldn't resolve `@blamejs/core` because the workflow ran the validator without first installing the wiki workspace deps. The step now runs `npm install --silent` in `examples/wiki/` before invoking the validator. The job was also renamed from "Wiki primitive-section convention" to reflect the source-driven shape. (b) Gitleaks re-flagged the v0.8.50 CHANGELOG entry — the prose quoted the same KEM-recipient destructure shape it was reporting fixed, retripping the generic-api-key rule on documentation text. The CHANGELOG entry was rewritten to avoid the literal token shape; `.gitleaks.toml` adds a fingerprint suppression for the historical v0.8.50 commit. No primitive surface change versus v0.8.50.
|
|
12
18
|
- v0.8.50 (2026-05-09) — CI green-up for v0.8.49. The v0.8.49 push tripped two CI gates: (a) `.github/workflows/ci.yml` still invoked `examples/wiki/test/validate-primitive-sections.js`, which the source-driven migration retired; the workflow step now runs `validate-source-comment-blocks.js` and runs `npm install` in `examples/wiki/` first so the validator can resolve `@blamejs/core` for the opts probe. (b) Three gitleaks findings on JSDoc `@example` blocks the migration added: a fake hex token in `lib/api-key.js`, a Stripe-shaped redaction example in `lib/log-stream.js`, and a KEM-recipient destructure in `lib/crypto.js`. The examples were rewritten to use placeholder text; `.gitleaks.toml` broadens the recipient-shape allowlist regex to cover any sibling field name, adds `test/fixtures/.*` to the path allowlist (exploit-corpus fixtures), and pins the historical commit + per-finding fingerprints. No primitive surface change versus v0.8.49.
|
|
13
19
|
- v0.8.49 (2026-05-09) — wiki is now source-driven. Every page is generated at boot from JSDoc-style `@module` + `@primitive` comment blocks in `lib/`. The hand-authored seeders under `examples/wiki/seeders/prod/pages/` are gone (~40 files, ~13k lines deleted); pages are produced by `examples/wiki/lib/page-generator.js` walking parsed source comments. Sidebar nav, home-page card grid, and page-generator curation entries auto-derive from `@nav` / `@title` / `@card` / `@featured` / `@order` / `@slug` tags on `@module` blocks via `examples/wiki/lib/auto-site-entries.js`. Drift between code and docs is structurally impossible — the same diff that changes the function changes the documentation. Cross-cutting narrative content lives in `lib/wiki-concepts.js` `@concept` blocks. Reference pages are auto-harvested at boot from framework state by `examples/wiki/lib/harvest-{errors,env-vars,vendored-deps,cli}.js`. New validators replace the legacy hand-authored-seeder validator: `validate-source-comment-blocks.js` (schema, ordering, signature/code arity match, `@example` parses-as-JS, placeholder-pattern detectors, posture catalog, semver shape, cross-reference resolution, metadata completeness), `validate-site-coverage.js` (entry/page consistency invariants), `validate-nav-coverage.js` (live HTTP round-trip + populated content). Discoverer `find-missing-pages.js` walks `api-snapshot.json` and surfaces namespaces still needing `@module` blocks. The legacy `validate-primitive-sections.js` (1264 lines) and its child runner `run-example.js` (492 lines) retired. ~145 lib namespaces now carry `@primitive` blocks; ~24 marked `@featured` for the home-card grid. Backfill script `examples/wiki/scripts/backfill-module-metadata.js` populates `@nav` / `@title` / `@card` from a canonical hints table for one-shot bulk migration. `b.safeJson.canonical` signature now `(value)` (the unused `_opts` param dropped). No other primitive surface change versus v0.8.48.
|
package/index.js
CHANGED
|
@@ -109,6 +109,7 @@ var httpClient = require("./lib/http-client");
|
|
|
109
109
|
// implementation; httpClient stays free of an api-encrypt dependency.
|
|
110
110
|
httpClient.encrypted = require("./lib/middleware/api-encrypt").httpClient;
|
|
111
111
|
httpClient.cookieJar = require("./lib/http-client-cookie-jar");
|
|
112
|
+
httpClient.cache = require("./lib/http-client-cache");
|
|
112
113
|
var websocket = require("./lib/websocket");
|
|
113
114
|
var sse = require("./lib/sse");
|
|
114
115
|
var mcp = require("./lib/mcp");
|
|
@@ -168,6 +169,7 @@ var auth = {
|
|
|
168
169
|
password: require("./lib/auth/password"),
|
|
169
170
|
totp: require("./lib/totp"),
|
|
170
171
|
passkey: require("./lib/auth/passkey"),
|
|
172
|
+
fidoMds3: require("./lib/auth/fido-mds3"),
|
|
171
173
|
jwt: Object.assign({},
|
|
172
174
|
require("./lib/auth/jwt"),
|
|
173
175
|
{ verifyExternal: require("./lib/auth/jwt-external").verifyExternal }),
|
|
@@ -199,7 +201,10 @@ var csv = require("./lib/csv");
|
|
|
199
201
|
var time = require("./lib/time");
|
|
200
202
|
var uuid = require("./lib/uuid");
|
|
201
203
|
var mail = require("./lib/mail");
|
|
204
|
+
var mailArf = require("./lib/mail-arf");
|
|
202
205
|
var mailBounce = require("./lib/mail-bounce");
|
|
206
|
+
var mailMdn = require("./lib/mail-mdn");
|
|
207
|
+
var publicSuffix = require("./lib/public-suffix");
|
|
203
208
|
var pubsub = require("./lib/pubsub");
|
|
204
209
|
var websocketChannels = require("./lib/websocket-channels");
|
|
205
210
|
var nonceStore = require("./lib/nonce-store");
|
|
@@ -396,7 +401,10 @@ module.exports = {
|
|
|
396
401
|
time: time,
|
|
397
402
|
uuid: uuid,
|
|
398
403
|
mail: mail,
|
|
404
|
+
mailArf: mailArf,
|
|
399
405
|
mailBounce: mailBounce,
|
|
406
|
+
mailMdn: mailMdn,
|
|
407
|
+
publicSuffix: publicSuffix,
|
|
400
408
|
pubsub: pubsub,
|
|
401
409
|
websocketChannels: websocketChannels,
|
|
402
410
|
nonceStore: nonceStore,
|
package/lib/audit.js
CHANGED
|
@@ -288,6 +288,10 @@ var FRAMEWORK_NAMESPACES = [
|
|
|
288
288
|
"router", // b.router (router.redirect.cross_origin.refused / allowed)
|
|
289
289
|
"http2", // b.router h2 GOAWAY tracker (http2.window_update.refused — CVE-2026-21714)
|
|
290
290
|
"tenant", // b.tenantQuota (tenant.quota.exceeded / tenant.budget.exceeded / tenant.crossover)
|
|
291
|
+
"httpclient", // b.httpClient.cache (httpclient.cache.hit / .miss / .stale / .revalidated / .evicted — RFC 9111 outbound HTTP cache)
|
|
292
|
+
"mailmdn", // b.mailMdn (mailmdn.generated / mailmdn.suppressed — RFC 3798/8098 Message Disposition Notification)
|
|
293
|
+
"mailarf", // b.mailArf (mailarf.parsed / mailarf.malformed — RFC 5965 abuse-feedback ingestion)
|
|
294
|
+
"mailbimi", // b.mail.bimi (mail.bimi.vmc.fetched / verified — RFC 9091 VMC chain validation)
|
|
291
295
|
];
|
|
292
296
|
var registeredNamespaces = new Set(FRAMEWORK_NAMESPACES);
|
|
293
297
|
|