@blamejs/core 0.8.52 → 0.8.58
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/db-collection.js +290 -0
- package/lib/db-query.js +245 -0
- package/lib/db.js +173 -67
- 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/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/mtls-ca.js +15 -5
- 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.58 (2026-05-09) — `b.db` query-builder + facade extensions for HermitStash-shaped migrations + adjacent gaps. **Query atoms** on `b.db.from(table)`: `.increment(column, delta)` (atomic `UPDATE col = COALESCE(col, 0) + ?`, refuses unconditional, returns rows-changed), `.whereGroup(qb => ...)` (closure-form OR composition via new `WhereBuilder` class with `.eq` / `.neq` / `.gt` / `.gte` / `.lt` / `.lte` / `.in` / `.like` AND vs `.orEq` / `.orNeq` / ... OR + `.raw`), `.orWhere(...)` (top-level OR; accepts object map / `(field, value)` / `(field, op, value)` / closure), `.search(fields, term, opts?)` (chainable LIKE-OR with `match: "substring"|"prefix"|"exact"`, `~` ESCAPE char to safely handle user-supplied `%`/`_`), `.paginate(opts)` (returns `{ items, total, limit, offset, page, totalPages }`; default limit 25, cap 1000). **Mongo facade** at `b.db.collection(name)` returning `{ insert, insertMany, find, findOne, update, updateMany, remove, count, paginate }` — maps Mongo-shape calls onto `b.db.from(name)`. Update operators: `$set` / `$inc` (composes `Query.increment`) / `$unset`. Query operators: `$eq` / `$ne` / `$gt` / `$gte` / `$lt` / `$lte` / `$in` / `$like`. Unknown operators throw at config-time. **db.init opt-outs**: `frameworkTables: false` skips provisioning `audit_log` / `consent_log` (operators with their own audit chain reuse the framework's `b.db` / `b.vault` / `b.cryptoField` primitives without the bundled chain tables — append-only triggers, chain verifies, WORM assertions, audit-signing bootstrap, checkpoint verifies, and the `audit_log` / `consent_log` reserved-name refusal all become no-ops). `auditSigning: false` (finer-grained — keep framework tables but skip the audit-signing-key bootstrap when the host manages its own signing key). **db.init path overrides**: `encryptedDbPath` (fully-qualified path to `db.enc`), `encryptedDbName` (basename under `dataDir`, default `"db.enc"`), `dbKeyPath` (encryption-key file outside `dataDir`, e.g. KMS-fronted volume). **`b.db.snapshot()`** — in-memory encrypted Buffer (same envelope `flushToDisk` writes, just held in memory; WAL checkpoint forced first so committed state captures cleanly). Plain mode returns the raw plaintext SQLite file. **`b.mtlsCa.create({ paths })` absolute-path fix** — `_resolvePaths` no longer joins absolute path entries under `dataDir`. The pre-v0.8.58 shape silently rewrote `MTLS_CA_KEY=/etc/ssl/ca.key` → `<dataDir>/etc/ssl/ca.key`, breaking operators with externally-mounted CA files. Standard `path.join` semantics already preserve absolute arguments — the always-join was an oversight. Relative entries still join under `dataDir` (back-compat). **CLAUDE.md release workflow §5** rewritten — host smoke + host wiki e2e (Phase A) run BEFORE container smoke + container wiki e2e (Phase B), sequentially, never in parallel. Both runners write to `.test-output/smoke.log` and `.test-output/wiki-e2e.log`; parallel runs clobber each other so the log of the actually-blocking failure may be overwritten by whichever leg finishes second. Phase B uses `smoke-container.log` / `wiki-e2e-container.log` so diagnose-after-failure is one file lookup. New per-primitive Layer 0 tests: `db-query-extensions.test.js` (27 checks), `db-collection.test.js` (23 checks), `db-init-extensions.test.js` (13 checks), `mtls-ca-paths.test.js` (7 checks). G7 (configurable framework-schema column names) deferred — original message cut off at the heading; re-open with the full proposal. G3 (configurable framework-table names — the `audit_log` / `consent_log` rename) deferred — `frameworkTables: false` covers the audit-conflict use case; full rename touches ~47 hardcoded SQL literals across `lib/audit*.js` / `lib/consent.js` and is its own patch with a refactor proper.
|
|
12
|
+
- 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.
|
|
13
|
+
- 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.
|
|
14
|
+
- 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.
|
|
15
|
+
- 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.
|
|
16
|
+
- 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.
|
|
11
17
|
- 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.
|
|
12
18
|
- 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.
|
|
13
19
|
- 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.
|
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
|
|