@blamejs/core 0.8.68 → 0.8.71

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,9 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.8.x
10
10
 
11
+ - v0.8.71 (2026-05-10) — CI green-up for v0.8.70. The v0.8.70 npm-publish workflow's cosign-sign-blob step couldn't resolve `sigstore/cosign-installer@d7d6e07b3e89342f1d8bcd4f76c2fa5a9d1a1f7e` — the SHA was a typo, not a real commit on the action's repo. Replaced with the actual v3.7.0 commit SHA `dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da`. No primitive surface change versus v0.8.70.
12
+ - v0.8.70 (2026-05-10) — six-batch additive surface across OAuth/OIDC, FAPI 2.0, browser hardening, MCP safety, compliance postures, and supply-chain. **OAuth/OIDC**: `b.auth.oauth.parseCallback(query, opts?)` validates RFC 9207 AS Issuer Identifier (refuses iss-mismatch and OP `error=` redirects, optional `requireIssParam` to refuse missing iss), `parseJarmResponse(jwt, opts?)` decodes OAuth 2.0 JARM signed authorization responses, and `refreshAccessToken(token, { seen })` accepts an operator-supplied callback that refuses replayed refresh tokens before any HTTP call (RFC 9700 §4.13 / OAuth 2.1 §6.1 one-time-use rotation; returns `refreshTokenRotated: true` on success). **FAPI 2.0 runtime**: `b.fapi2.assertCallback(query)` refuses missing iss when `fapi-2.0` posture is set (and refuses bare-param when `fapi-2.0-message-signing` is set, requiring JARM `response`); `b.fapi2.assertAuthzRequest(authzParams)` refuses non-JAR (bare-param) authorization requests under FAPI 2.0. New `fapi-2.0-message-signing` posture registered. **Browser hardening**: `Permissions-Policy` defaults extend with `storage-access=()`, `browsing-topics=()`, `private-aggregation=()`, `controlled-frame=()`, `captured-surface-control=()`; `b.middleware.cors` gains `allowPrivateNetwork` opt + Private Network Access preflight handling (refuses `Access-Control-Request-Private-Network` by default, sets `Access-Control-Allow-Private-Network: true` when opted in); `b.middleware.requireAuth` / `requireAal` / `requireStepUp` 401 responses now set `Cache-Control: no-store` (RFC 9111 §5.2.2.5). **MCP safety + LLM07/08**: `b.mcp.toolResult.sanitize(result, opts?)` runs prompt-injection regex + dangerous-HTML detection + URL-allowlist on tool outputs (modes `refuse` / `sanitize` / `audit-only`); `b.mcp.capability.create(scopes)` + `satisfiedBy(granted)` formalize least-privilege capability checks; `b.mcp.validateToolInput(toolName, input, schema)` enforces a JSON Schema 2020-12 subset on tool inputs (`type` / `properties` / `required` / `items` / `enum` / `const` / `minLength` / `maxLength` / `minimum` / `maximum`). **Compliance postures**: `modpa` (Maryland Online Data Privacy Act, US-MD privacy), `nydfs-500` (NY DFS Cybersecurity Regulation, US-NY financial), `hipaa-2026` (HHS Final Rule effective 2026, US health), `quebec-25` (Quebec Law 25, CA-QC privacy), and `fapi-2.0-message-signing` (INTL financial). **EU Data Act** (Regulation 2023/2854): new `b.dataAct` primitive — `declareProduct`, `recordUserAccess`, `shareWithThirdParty` (Art 32 §1 refuses sharing with DMA designated gatekeepers without an audited override `acceptGatekeeper.reason`), `recordSwitchRequest` (Art 28 §3 caps notice period at 30 days). **Supply chain**: SBOM bumped to CycloneDX 1.6; npm-publish workflow now runs OSV-Scanner with `--fail-on-vuln=HIGH`, signs the SBOM via Sigstore cosign keyless flow (attaches `.sigstore` bundle to the GH release alongside the JSON); `scripts/publish-dep-confusion-placeholder.sh` claims unscoped names (`blamejs`, `blame-js`, `blamejs-core`) on npm with placeholder packages that exit-1 + redirect to canonical `@blamejs/core` (defends against dependency-confusion typosquats — manual, run on maintainer rotation, refuses overwrite when a different owner already holds the name).
13
+ - v0.8.69 (2026-05-10) — test-side `waitUntil` helper + CLAUDE.md §11b convention. Every recurring "test passes alone, fails under SMOKE_PARALLEL=64 / macOS GitHub-Actions runner" flake we've fought across v0.8.55 (rate-limit-cluster), v0.8.60 (watcher), v0.8.63 / v0.8.65 / v0.8.68 (log-stream-otlp / sandbox) was the same root cause: a fixed-budget `setTimeout(r, N)` sleep too short for runner-contention reality. New `test/helpers/wait.js` ships `waitUntil(predicate, opts?)` (polls every `intervalMs` default 25ms up to `timeoutMs` default 5000ms, exits early when predicate truthy, throws labeled error on timeout) + `waitUntilEqual(getter, expected)` convenience wrapper. `test/helpers/index.js` re-exports both. Refactored `test/layer-0-primitives/log-stream-otlp.test.js`'s "collector saw retries" gate (the most-recently-flaked one) to use `waitUntil({ failCount >= 2, dropEvents.length === 1 })` instead of `_sleep(200)` — fast platforms exit in ~30ms, contended platforms get the full budget. CLAUDE.md §11b documents the convention: when you find yourself bumping a hand-tuned sleep to fix a CI flake, that's the smell — convert to `waitUntil`. Future flake fixes update one timeout ceiling instead of N inline budgets.
11
14
  - v0.8.68 (2026-05-10) — `b.watcher` polling backend for environments where `fs.watch` doesn't deliver events. Pre-v0.8.68 the watcher used `fs.watch(root, { recursive: true })` exclusively — works on real Linux/macOS/Windows kernels but silent on filesystems where the kernel→userspace event bridge doesn't exist: Docker Desktop bind-mounts on Windows / macOS hosts (gRPC-FUSE / VirtioFS doesn't propagate inotify events from the Linux container's mount through to the host fs the operator runs node on), NFS / SMB mounts, some FUSE filesystems. Add `mode: "fs" | "poll"` (default `"fs"`) — when `mode: "poll"`, the watcher walks the tree on a fixed interval and diffs against the previous snapshot. New file / mtime-change / size-change → `onChange` via the existing debounce + ignore + lstat dispatch; missing path → `onDelete`. `pollIntervalMs` (default 1s) sets cadence; `pollMaxFiles` (default 50000) caps the per-tick walk so a misconfigured root can't stall the event loop stat'ing 100k files every second — overflow refuses with `watcher/poll-overflow`. Symlinks skipped (matches fs.watch path). The initial walk happens synchronously in `create()` so the first event fires only on real post-start changes (not on pre-existing files). `_flushForTest()` runs one synchronous tick + drains pending debounces so polling tests don't have to sleep `pollIntervalMs`. Returned handle gains `.mode` for operator introspection. fs.watch-backend error messages now suggest `mode: "poll"` as the fallback. New Layer 0 polling tests cover create / modify / delete detection across nested directories + mode validation + pollMaxFiles overflow.
12
15
  - v0.8.67 (2026-05-10) — SAML XMLDSig Reference Transforms (`enveloped-signature` + per-Reference c14n) + full IdP-emitted SAML round-trip in the federation-auth integration test. Pre-v0.8.67 `b.auth.saml.sp.verifyResponse` only honored the SignedInfo's `CanonicalizationMethod`; it didn't process the `<ds:Transforms>` block on the Reference. Real-world IdP-signed responses (Keycloak, ADFS, Okta) attach `http://www.w3.org/2000/09/xmldsig#enveloped-signature` (strip the `<Signature>` child of the referenced element before c14n) and a per-Reference `xml-exc-c14n#` Transform — without them, the digest computed over the assertion-including-signature never matches the signed-then-signature-injected reality and verifyResponse rejected legitimate IdP responses. `_verifyXmldsig` now reads the Transforms list, applies enveloped-signature by filtering the parsed-tree's `<Signature>` element children before canonicalization, and honors the per-Reference c14n choice (with vs without comments). The single-match-by-ID invariant + signature-wrapping defense moves into the saml.js path directly so the modified subtree (signature stripped) is the one that gets canonicalized + digested. `test/integration/federation-auth.test.js` now drives Keycloak's HTML login form via cookie-jar curl-equivalent (no headless browser needed), captures the IdP-signed SAMLResponse, fetches the IdP signing certificate from `/protocol/saml/descriptor`, hands the response to `sp.verifyResponse(b64, { expectedInResponseTo })`, and asserts the extracted `nameId` / `issuer` / `audience` / `inResponseTo` match the realm's signed claims. Verified end-to-end: Keycloak alice user → SAML AuthnRequest → login form POST → signed Response → `sp.verifyResponse()` → `{ nameId: "alice", issuer: <realm>, audience: <SP entityID>, attributes: { Role: "default-roles-..." } }`. Unsupported Transform algorithms refuse loudly via `auth-saml/unsupported-transform`. No primitive surface change versus v0.8.66 (the Transforms processing is internal to `_verifyXmldsig`).
13
16
  - v0.8.66 (2026-05-10) — `b.session.updateData(token, data, opts?)`. Update the sealed `data` payload on a session WITHOUT rotating the sid. Pre-v0.8.66 the only path to mutate session data was `b.session.rotate(token, { data })` which forces an sid rotation — appropriate for security-boundary transitions (login, MFA, role escalation) but heavyweight for cart-state writes / preference flips / step-up-completion flags. Default semantics: full payload replace, `lastActivity` bumped (idle-timeout reset), reserved `__bj_fingerprint` binding preserved automatically so verify() still surfaces drift correctly. `opts.merge: true` does a one-level deep merge into the existing payload; `opts.touchLastActivity: false` skips the idle-timeout bump. Returns `false` for unknown / expired / pre-v0.8.61-raw-format tokens (no throw). Anonymous-session userIds work the same as named userIds. Leader-only. New Layer 0 tests: 13 checks covering replace / merge / null-clear / fingerprint preservation / unknown-token returns / array refusal.
package/README.md CHANGED
@@ -1,9 +1,26 @@
1
+ <div align="center">
2
+
3
+ <img src="assets/BlameJS_Logo.png" alt="blamejs" width="220" />
4
+
1
5
  # blamejs
2
6
 
3
7
  **The Node framework that owns its stack.**
4
8
 
5
9
  One install. One upgrade path. One place to look when something breaks — no blame to pass between forty transitive dependencies you didn't choose.
6
10
 
11
+ [![npm version](https://img.shields.io/npm/v/@blamejs/core.svg?label=%40blamejs%2Fcore&color=d946ef)](https://www.npmjs.com/package/@blamejs/core)
12
+ [![npm downloads](https://img.shields.io/npm/dm/@blamejs/core.svg?color=d946ef)](https://www.npmjs.com/package/@blamejs/core)
13
+ [![CI](https://img.shields.io/github/actions/workflow/status/blamejs/blamejs/ci.yml?branch=main&label=CI)](https://github.com/blamejs/blamejs/actions/workflows/ci.yml)
14
+ [![release](https://img.shields.io/github/v/release/blamejs/blamejs?include_prereleases&sort=semver)](https://github.com/blamejs/blamejs/releases)
15
+ [![OpenSSF Scorecard](https://api.scorecards.dev/projects/github.com/blamejs/blamejs/badge)](https://scorecard.dev/viewer/?uri=github.com/blamejs/blamejs)
16
+ [![SLSA Level 3](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev)
17
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
18
+ [![node](https://img.shields.io/node/v/@blamejs/core.svg)](https://nodejs.org)
19
+ [![Zero runtime deps](https://img.shields.io/badge/runtime%20deps-0-2ea043)](#why-blamejs)
20
+ [![PQC-first](https://img.shields.io/badge/crypto-PQC--first-d946ef)](#why-blamejs)
21
+
22
+ </div>
23
+
7
24
  ---
8
25
 
9
26
  ## Why blamejs
@@ -41,19 +58,147 @@ var b = require("@blamejs/core");
41
58
 
42
59
  The framework bundles the surface a typical Node app reaches for. Every primitive listed is callable today; nothing is a stub.
43
60
 
44
- - **Data layer** — SQLite with sealed-by-default columns (`b.db`), migrations, seeders, atomic-file writes; chainable query builder with atomic `.increment(col, delta)`, closure-form `.whereGroup` / top-level `.orWhere` OR composition, `.search(fields, term)` LIKE-OR with safe `%`/`_` ESCAPE handling, `.paginate(opts)` returning `{ items, total, page, totalPages }`; Mongo-style document-store facade `b.db.collection(name, opts?)` (`$set` / `$inc` / `$unset` / `$eq` / `$ne` / `$gt` / `$gte` / `$lt` / `$lte` / `$in` / `$like`) with schemaless-document opts — `overflow: "<col>"` folds unknown insert/update fields into a JSON-text column (and rewrites `WHERE` on virtual fields to `JSON_EXTRACT`), `jsonColumns: [...]` auto-stringifies on write + parses via `b.safeJson` on read, `sealedFields: { email: "emailHash" }` co-locates a `b.cryptoField` sealed-column / derived-hash declaration with the collection so plaintext lookups auto-rewrite to hash-column lookups; in-memory encrypted snapshot via `b.db.snapshot()`; standalone encrypted-DB-file lifecycle for consumers that own their own SQLite handle (`b.db.fileLifecycle({ dataDir, vault })` — decrypt-to-tmpfs, periodic re-encrypt flush, snapshot, graceful shutdown — same envelope as `b.db`, no schema/audit-chain coupling); `db.init` opt-outs for hosts that own their audit chain (`frameworkTables: false` / `auditSigning: false`) and configurable encrypted-file paths (`encryptedDbPath` / `encryptedDbName` / `dbKeyPath`); bring-your-own external Postgres / MySQL / etc. with pool tuning + role-aware connect + read-replica routing (`b.externalDb`); declarative role-narrowed views and Postgres row-level-security migrations (`b.db.declareView`, `b.db.declareRowPolicy`); S3 / R2 / B2 / GCS / Azure object store with multipart upload + SSE + bucket-ops (create / delete / list / lifecycle / CORS) across all three clouds, plus S3 Object Lock + per-object retention + legal hold for write-once-read-many compliance workloads (`b.storage`, `b.objectStore`); durable queue with priority + cron + flows on the local SQLite backend, a shared Redis backend, OR AWS SQS via SigV4 + AWSJsonProtocol_1.0 for fully-managed multi-replica deploys (`b.queue`, `b.jobs`); cluster-shared cache (`b.cache`).
45
- - **Identity & access** — passwords (Argon2id) + policy primitive (NIST 800-63B / PCI-DSS 4.0 / HIPAA-AAL2 profiles, HaveIBeenPwned k-anonymity breach check, length / context / dictionary / complexity rules, rotation + history) (`b.auth.password`); passkeys (WebAuthn), TOTP, JWT (PQ-default), OAuth + OIDC RP-Initiated / Front-Channel / Back-Channel Logout 1.0 (`b.auth.oauth.parseFrontchannelLogoutRequest` + `verifyBackchannelLogoutToken` with jti-replay defense), CIBA Core 1.0 decoupled-auth client (`b.auth.ciba`, poll/ping/push delivery, JWT-bearer / mTLS / shared-secret client auth), OpenID Federation 1.0 trust chain (`b.auth.openidFederation`, entity statement parse + verify, metadata_policy resolution), SAML 2.0 SP with XMLDSig signature-wrapping defense via single-match-by-ID invariant + RFC 9525 server-identity (`b.auth.saml`), OpenID4VCI 1.0 issuer (`b.auth.oid4vci` — credential_offer / pre-authorized_code / /credential with proof-JWT verification), OpenID4VP 1.0 verifier with DCQL query language (`b.auth.oid4vp`), SD-JWT VC with optional `key_attestation` extension for TEE / FIDO MDS3 / App Attest holder-key provenance (`b.auth.sdJwtVc`), sessions with PQC-sealed sid cookie (ML-KEM-1024 + P-384 hybrid + XChaCha20-Poly1305 envelope on the wire), `/24` IPv4 + `/64` IPv6 subnet binding via `fingerprintFields: ["clientIpPrefix"]` (carrier-roaming-safe), pluggable storage backend via `b.session.useStore` + first-party `b.session.stores.localDbThin` (tmpfs-fast session writes that don't fight the main DB's encrypted-at-rest re-flush cycle), opaque-userId anonymous sessions via `b.session.create({ anonymous: true })`, idle / absolute timeouts, optional fingerprint drift detection + anomaly scoring, brute-force lockout (`b.auth.*`, `b.session`); RBAC + optional per-role DB binding + role-spec `requireMfa` + per-route MFA freshness window + ABAC predicate registry (`b.permissions`); API keys with rotation (`b.apiKey`); break-glass column gates with second-factor + audit (`b.breakGlass`); two-person-rule approval workflow with m-of-n quorum + cooling-off lock + approver-role gate + cancellation (`b.dualControl`); FAPI 2.0 Final composite posture (PAR + PKCE-S256 + DPoP-or-mTLS sender-constrained tokens + RFC 9207 issuer-in-callback) for financial / Open Banking deployments (`b.fapi2`); CFPB §1033 / FDX 6.0 consumer-financial-data-sharing wrapper (`b.fdx`); cross-table data-subject coordination (export / rectify / erase / restrict / objection) walking every table tagged with the subject's column without app-side plumbing (`b.subject`, `b.subject.eraseHard`); subject-level legal-hold registry consulted by erase + retention paths (FRCP Rule 26/37(e), GDPR Art 17(3)(e), SEC Rule 17a-4, HIPAA §164.530(j)(2)) (`b.legalHold`); adaptive bot-challenge staircase composing `b.middleware.botGuard` + `b.auth.lockout` + operator challenge / escalation hooks for auth paths (`b.authBotChallenge`); session-to-device-posture binding (UA + Accept-Language + Accept-Encoding + IP /24 prefix + optional WebAuthn-bound key) with fail-closed verify on store error (`b.sessionDeviceBinding`).
46
- - **Crypto** envelope-versioned PQC at rest (ML-KEM-1024 + P-384 hybrid, XChaCha20-Poly1305, SHAKE256), vault sealing, field-level crypto + cryptographic erasure (`b.cryptoField.eraseRow`), per-column data residency tagging + per-row keys (`K_row = HKDF(K_table, rowId)`) so erasing the per-row key makes WAL / replica residuals undecryptable true crypto-shred discipline (`b.cryptoField.declareColumnResidency`, `b.cryptoField.declarePerRowKey`); AAD-bound sealed columns whose AEAD tag is tied to a `(table, rowId, column, schemaVersion)` tuple so a copy-paste between rows or a schema-version replay surfaces as a refused decrypt (`b.vault.aad`); signed webhooks (SLH-DSA-SHAKE-256f default; ML-DSA-65 opt-in for smaller signatures + faster verify), ECIES API encryption (`b.crypto`, `b.vault`, `b.webhook`); RFC 9180 HPKE with ML-KEM-1024 + HKDF-SHA3-512 + ChaCha20-Poly1305 suite (`b.crypto.hpke`); RFC 9421 HTTP Message Signatures with derived components (`@method`, `@target-uri`, `@authority`, `@path`, `@query`) and `created` / `expires` / `nonce` / `keyid` parameters; ed25519 (legacy peers) + ML-DSA-65 (PQC peers) (`b.crypto.httpSig`); RFC 9266 TLS-Exporter channel binding for token-to-session pinning (`b.tlsExporter`); RFC 9162 CT v2 inclusion-proof verification against signed tree heads (`b.network.tls.ct.verifyInclusion`); RFC 8555 ACME client + RFC 9773 ARI (Renewal Information) polling for the CA/Browser Forum 47-day certificate lifetime (`b.acme`); RFC 8470 0-RTT inbound posture (`refuse` default; `replay-cache` opt-in with 10s SHA3-512 dedupe window; fail-closed under `pci-dss` / `fapi2`) (`b.router.create({tls0Rtt})`); RFC 9794 SecP256r1MLKEM768 codepoint added to the preferred-group order (`b.network.tls.preferredGroups`); pure-JS mTLS CA that issues clientAuth / serverAuth / dual-EKU certs with SAN entries and auto-detects the highest-PQC signature algorithm the vendored x509 library accepts (today: ECDSA-P384-SHA384 bridge; self-upgrades to SLH-DSA / ML-DSA when the X.509 ecosystem catches up), PQC TLS gates inbound + outbound (`b.mtlsCa`, `b.pqcGate`, `b.pqcAgent`).
47
- - **HTTP** — router with schema-validated routes + OpenAPI publication (`b.openapi`) + AsyncAPI publication for event/streaming endpoints (`b.asyncapi`); full middleware stack (CSRF, CORS, rate-limit, security headers, CSP nonce, body parser, compression, SSE, request log, threat-aware cookie parser via `b.middleware.cookies`, request-time DB role binding via `b.middleware.dbRoleFor`, in-process CIDR fence via `b.middleware.networkAllowlist`) wired by `createApp`; HTTP/1.1 + HTTP/2 outbound client with SSRF gate (cloud-metadata IPs hard-denied unconditionally; private / loopback / link-local overridable per call), scheme + userinfo + per-host (wildcard / per-method) destination allowlist, redirects, multipart, interceptors, progress, encrypted cookie jar (`b.httpClient`, `b.ssrfGuard`, `b.safeUrl`); operator-tunable network configurability env-driven NTP / NTS (RFC 8915 authenticated time), IPv4-or-IPv6 NTP servers, DNS with IPv6 / DoH / DoT (private-CA trust pinning via `opts.ca`) / cache / lookup timeout, outbound HTTP proxy (`HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`), runtime DPI trust-store CA additions, application-level heartbeats, TCP socket defaults (`b.network`); operator-rendered error pages with no app-frame leakage (`b.errorPage`).
48
- - **Defensive parsers** — `b.safeJson` (with `maxKeys` cap defending CVE-2026-21717 V8 HashDoS), `b.safeBuffer`, `b.safeSql`, `b.safeSchema`, `b.safeUrl` (IDN mixed-script / homograph refuse), `b.safeJsonPath` (JSON-path validator refusing filter `?(...)`, deep-scan `$..`, script-shape `(@.x)` for safe Postgres JSONB ops), `b.parsers` (XML / TOML / YAML / .env), `b.config` (schema-validated env), `b.fileType` magic-byte content classification with deny-on-upload categories (image / document / archive / executable / etc.).
49
- - **Content-safety gates** — `b.gateContract` uniform composition contract (mode posture / hooks / forensic snapshot / decision cache / runtime cap). Family members: `b.guardCsv` (formula injection ASCII + full-width prefixes, dangerous-function denylist, bidi / homoglyph / control / null / BOM / zero-width detection, dialect ambiguity, CSV-bombs, numeric precision, schema-bound serializer); `b.guardHtml` (XSS / mXSS / DOM-clobbering / dangerous-tag / event-handler-family / dangerous-URL-scheme with entity-decode / CSS-injection in style attribute / IE conditional comments + token-level sanitize + always-correct `escapeText` / `escapeAttr` entity encoders); `b.guardSvg` (script / foreignObject / animation-element href hijack / DOCTYPE billion-laughs / XXE / SVGZ / cross-origin `<use>` SSRF / event-handlers + token-level sanitize). `b.guardArchive` (zip-slip / symlink + hardlink escape / decompression-ratio bombs (per-entry + aggregate) / nested-archive depth / duplicate-entry / case-insensitive collision / encryption-claim mismatch / format-claim mismatch via magic-byte detection — composes `b.guardFilename` for per-entry-name validation); `b.guardJson` (source-level prototype-pollution detection, duplicate-key, NaN/Infinity, JSON5 syntax, BOM, bidi, numeric-precision-loss, top-level-key allowlist, depth/breadth/array/string/node-count caps); `b.guardYaml` (deserialization-tag RCE via language-specific tag prefixes, billion-laughs alias recursion, Norway-problem implicit booleans, leading-zero octals, multi-document streams, duplicate keys, merge-key chains, depth+anchor+node caps); `b.guardXml` (XXE / billion-laughs / external-entity / parameter-entity / XInclude / xsi:schemaLocation / processing-instruction / CDATA / XML-signature-wrapping detection — DOCTYPE refused at all profile levels); `b.guardMarkdown` (source-level scan run BEFORE any markdown renderer sees the input — dangerous URL schemes in inline links + images + autolinks + reference-link definitions with HTML-entity decode bypass; whitespace-tolerant dangerous-tag matching per CVE-2026-30838; front-matter; HTML comments; code-fence language injection; catastrophic emphasis-run ReDoS per CVE-2025-6493 class; inline DOCTYPE; depth + link + image + autolink + ref-def caps); `b.guardEmail` (single-address + full RFC 822/5322 message validation — SMTP smuggling per CVE-2023-51764 / 51765 / 51766 / CVE-2026-32178 class via bare-CR + bare-LF + smuggled SMTP verbs; CRLF header injection; IDN homograph mixed-script domains with operator-opt-in `allowedScripts`; Punycode flag; display-name spoofing; IP-literal addresses; RFC 5322 comment syntax; multi-@; RFC 5321 length caps + RFC 5322 line cap; BOM injection). Filename safety: `b.guardFilename` (path traversal raw + percent-encoded + overlong-UTF-8 + null-byte truncation + Windows reserved names + NTFS ADS + RTLO bidi spoofing + shell-exec / double-extension detection — standalone, wires into `b.fileUpload` via `filenameSafety`). All members ship strict / balanced / permissive profiles plus hipaa / pci-dss / gdpr / soc2 compliance postures. `b.guardAll` is the registry + aggregator: every shipped guard ON by default; opt-out per guard with audited reason via `exceptFor: { name: { reason } }`. **As of v0.7.12, `b.fileUpload` and `b.staticServe` wire `b.guardAll.byExtension({ profile: "strict" })` automatically + `b.fileUpload` also wires `b.guardFilename.gate({ profile: "strict" })` as `filenameSafety`** — defense-in-depth applied without any explicit operator wiring. Operators opt out per host-primitive via `contentSafety: null` / `filenameSafety: null` (audited at create() with operator-supplied reason).
50
- - **Communication** — WebSockets with channel/room fan-out across cluster replicas + RFC 6455 §5.5 control-frame size + FIN enforcement on inbound (defends 1 MiB-PING-echoed-as-PONG 2× amplification class) (`b.websocket`, `b.websocketChannels`); outbound WebSocket client (RFC 6455) with PQC-TLS handshake, permessage-deflate negotiation with decompression-bomb cap, fatal UTF-8 validation, control-frame size + FIN enforcement, permanent-error classifier that skips reconnect on 4xx handshake / accept mismatch / bad-subprotocol, exponential-backoff with full jitter (`b.wsClient`); generic distributed pub/sub with cluster-table / Redis PUB/SUB / custom backends (`b.pubsub`); framework-emitted signal bus for breach / integrity events (audit-chain break, vault-seal failure, honeytoken trip, etc.) routed to operator-wired listeners (`b.events`); CloudEvents 1.0 envelope wrapper for outbound events to AWS EventBridge / Knative / Azure Event Grid / Google Eventarc / CNCF event consumers (`b.cloudEvents`); Server-Sent Events with newline-injection refusal in `event:` / `id:` / `data:` / `Last-Event-ID` per CVE-2026-33128 / 29085 / 44217 class (`b.sse`, `b.middleware.sse`); mail with multipart + attachments + DKIM + calendar invites + bounce intake (`b.mail`, `b.mailBounce`); inbound mail authentication — SPF / DMARC / ARC verify + ARC chain signing for relays (`b.mail.spf`, `b.mail.dmarc`, `b.mail.arc`); generic notification dispatcher with operator-supplied transports (`b.notify`); TCPA / FCC 1:1 prior-express-written-consent record audit + 10DLC carrier-shaped consent snapshot for SMS marketing (`b.tcpa10dlc`); chunked file uploads with per-chunk SHA3-512 verification + atomic finalize + tombstone cleanup (`b.fileUpload`).
51
- - **AI / agentic** — Model Context Protocol server-guard with bearer auth + redirect_uri allowlist + dynamic-register refusal + tool/resource allowlists (CVE-2026-33032 / CVE-2025-6514 / confused-deputy class) (`b.mcp.serverGuard`); GraphQL Federation `_service.sdl` trust-boundary with router-token + nonce store (`b.graphqlFederation`); prompt-injection input classifier (OWASP LLM01:2025 / NIST COSAIS RFI) (`b.ai.input.classify`); A2A signed agent-card primitive (Linux Foundation Agentic AI Foundation v1.x, ML-DSA-87) (`b.a2a`); C2PA 2.1 + California SB-942 / AB-853 content-provenance manifest builder for AI-generated media embeds provider name, model identifier + version, content timestamp, unique content ID as a signed manifest (`b.contentCredentials`).
52
- - **Compliance regimes** — top-level posture coordinator that fans an operator-declared regime (`hipaa` / `pci-dss` / `gdpr` / `soc2` / `sox-404` / `soc2-cc1.3` / `dora` / `nis2` / `cra` / `fapi2` / `fdx` / `sec-cyber` / `sec-17a-4` / `finra-4511` / `fda-21cfr11` / `fda-annex-11` / `dsr` / `dpdp` / `pipl-cn` / `lgpd-br` / `appi-jp` / `pdpa-sg` / `staterramp` / `irap` / `bsi-c5` / `ens-es` / `uk-g-cloud` / etc.) cascading into retention / audit / db / cryptoField via a POSTURE_DEFAULTS table (`b.compliance`); 21 CFR Part 11 §11.10(e) audit-content gate + §11.50(b) electronicSignature shape (`b.fda21cfr11`); PCI DSS 4.0 Req 10.4.1.1 daily-review automation cron-firing through `b.scheduler` with severity classification + operator notify on threshold (`b.auditDailyReview`); SOX §404 + SOC 2 CC1.3 segregation-of-duties on audit-log writers via Postgres trigger DDL refusing INSERTs whose actor doesn't match the SQL session role (`b.audit.bindActor`, `b.audit.assertSegregation`); m-of-n approver DDL change-control with maintenance-window enforcement and ML-DSA-87 signed proposals (`b.ddlChangeControl`); row-level WORM triggers boot-asserted under `sec-17a-4` / `finra-4511` / `fda-21cfr11` postures (`b.db.declareWorm`); dual-control physical delete + crypto-erase + REINDEX in one transaction (`b.db.declareRequireDualControl`, `b.db.eraseHard`); FTC click-to-cancel UX-parity attestation with `ftc-2024` / `ca-sb942` / `strict` postures (`b.darkPatterns`); GDPR Articles 15–22 / CCPA / CPRA / LGPD / PIPEDA data-subject-rights workflow with operator-supplied ticket store + per-source query / erase callbacks + deadline computation + audit emission (`b.dsr`); EU DORA Article 17 ICT-incident-reporting workflow per Commission Delegated Regulation 2024/1772 (initial / intermediate / final report shape) (`b.dora`); EU NIS2 reporter (`b.nis2`); EU Cyber Resilience Act SBOM + secure-software-attestation hooks (`b.cra`); SEC Form 8-K Item 1.05 cybersecurity-incident materiality-disclosure artifact generator (4-business-day filing window, AG delay request hook) (`b.secCyber`); IAB Europe Transparency & Consent Framework v2.3 consent-string parser + `disclosedVendors` validator (`b.iabTcf`); IAB MSPA / Global Privacy Platform universal-opt-out signal codec covering USNAT / USCA / USVA / USCO / USCT / USUT sections + GPC mirror (`b.iabMspa`); generic consent capture + withdrawal (`b.consent`); incident lifecycle coordinator (`b.incident`); outbound DLP classifier + redactor with built-in detectors for PAN (Luhn), SSN, EIN, IBAN (mod-97), api-key shapes, PEM, SSH private keys, JWTs, AWS access keys, PHI composite — interceptor-installed on httpClient + mail + webhook with refuse / redact / audit-only verdicts under pci-dss / hipaa / fapi2 / soc2 / gdpr posture presets (`b.redact.installOutboundDlp`).
53
- - **Observability** tamper-evident audit chain with SLH-DSA-signed checkpoints, metrics, tracing (OTel pass-through when wired), PII redaction, log-stream sinks (local file rotation, generic webhook, OTLP/HTTP-JSON OR OTLP/gRPC to an OTel collector, AWS CloudWatch Logs via SigV4 with optional autoCreate, RFC 5424 syslog over UDP/TCP/TLS), OTLP/HTTP-JSON exporter for traces + metrics (`b.audit`, `b.metrics`, `b.tracing`, `b.redact`, `b.logStream`, `b.otelExport`); CADF (ISO/IEC 19395:2017) audit envelope export for federated SIEM (`b.audit.export({ format: "cadf" })`); canary-credential / decoy-record framework that audits every positive lookup as `honeytoken.tripped` (`b.honeytoken`); operator-callable boot-time security policy assertions (`b.security.assertProduction`); tamper-evident config-baseline drift detection signed with the audit-signing key + at-boot vendor-bundle SHA-256 integrity verification across `lib/vendor/*` (`b.configDrift`, `b.configDrift.verifyVendorIntegrity`); CSP violation report intake middleware with per-directive aggregation (`b.middleware.cspReport`); post-incident audit-bundle composer for forensic export (`b.auditTools.forensicSnapshot`).
54
- - **i18n** — CLDR plural rules, Accept-Language negotiation, Intl formatters, RTL (`b.i18n`).
55
- - **Format helpers** — RFC 4180 CSV with Excel formula-injection prevention (`b.csv`), RFC 9562 UUID v4 + v7 (`b.uuid`), URL-safe slugs (`b.slug`), TZ-aware datetime (`b.time`), ZIP creation (`b.archive`), HMAC-signed cursor pagination (`b.pagination`), HTML form rendering + validation + CSRF (`b.forms`).
56
- - **Production** — cluster leader election with fenced leases over Postgres/SQLite (`b.cluster`); cron + interval scheduler that runs exactly-once globally (`b.scheduler`); retry with full-jitter backoff + circuit breaker (`b.retry`); graceful shutdown (`b.appShutdown`); NTP boot check (`b.ntpCheck`); transactional outbox + dedupe-on-receive inbox so the business-state change and the outbound publish (or the inbound mark-handled) live in the same DB transaction exactly-once semantics across Postgres / SQLite (`b.outbox`, `b.inbox`); end-to-end-encrypted backup bundles with pre-flush fail-closed mode + ML-DSA-87 signed manifests + scheduled backup-restore drills (`b.backup`, `b.backup.scheduleTest`, `b.backupBundle.verifyManifestSignature`); disaster-recovery runbook generator composing breach-disclosure deadlines, cluster topology, and backup config under HIPAA / PCI-DSS / GDPR / SOC 2 / DORA postures (`b.drRunbook`); restore with pulled-bundle footprint preflight (`b.restore`); per-tenant DB storage caps, query budgets, and tenant-isolation breach detection (`b.tenantQuota`); per-Postgres-role hardening with `pg_roles` enumeration guard refusing unrecognized roles (`b.externalDb.assertRoleHardening`); RFC 4180 strict CSV table export with SHA3-512 manifest + ML-DSA-87 signature, plus JSON Schema 2020-12 reflective metadata (`b.db.exportCsv`, `b.db.getTableMetadata`); Debezium-shape change-event envelope on the transactional outbox (`b.outbox.create({ envelope: "debezium" })`); GDPR / PCI / HIPAA-shaped retention rules with multi-stage warn → archive → erase, legal-hold exemptions, dry-run preview, cross-table cascade (`b.retention`); OpenFeature-spec feature-flag client with pluggable providers + evaluation-context targeting + per-request `req.flag` accessor (`b.flag`); per-resource concurrency lock with cooperative-cancel + audit (`b.resourceAccessLock`); composite account-takeover kill-switch — destroy all sessions + engage lockout + flip optional global access-lock mode + audit, in one call (`b.atoKillSwitch`); `worker_threads` sandbox for unsafe operator-supplied transforms with strict resource limits (`b.sandbox`, composable into `b.template.create({ sandbox: true })`); hardened `processSpawn` wrapper that refuses shell-string invocation and enforces argv-array form (`b.processSpawn`); per-host outbound destination allowlist (wildcard / per-method) wired through `b.httpClient.request({ allowedHosts: [...] })` so a compromised process can't reach arbitrary upstreams.
61
+ ### Data layer
62
+
63
+ - **SQLite with sealed-by-default columns** — `b.db`, migrations, seeders, atomic-file writes
64
+ - **Chainable query builder** — atomic `.increment(col, delta)`, closure-form `.whereGroup` / top-level `.orWhere` OR composition, `.search(fields, term)` LIKE-OR with safe `%`/`_` ESCAPE handling, `.paginate(opts)` returning `{ items, total, page, totalPages }`
65
+ - **Mongo-style document-store facade** — `b.db.collection(name, opts?)` with `$set` / `$inc` / `$unset` / `$eq` / `$ne` / `$gt` / `$gte` / `$lt` / `$lte` / `$in` / `$like`; schemaless-document opts via `overflow: "<col>"` (folds unknown fields into a JSON-text column; rewrites `WHERE` on virtual fields to `JSON_EXTRACT`), `jsonColumns: [...]` (auto-stringify on write + parse via `b.safeJson` on read), `sealedFields: { email: "emailHash" }` (co-locates a `b.cryptoField` sealed-column / derived-hash declaration so plaintext lookups auto-rewrite to hash-column lookups)
66
+ - **DB lifecycle** — in-memory encrypted snapshot via `b.db.snapshot()`; standalone encrypted-DB-file lifecycle (`b.db.fileLifecycle({ dataDir, vault })` decrypt-to-tmpfs, periodic re-encrypt flush, graceful shutdown same envelope as `b.db`, no schema/audit-chain coupling); `db.init` opt-outs `frameworkTables: false` / `auditSigning: false` and path overrides `encryptedDbPath` / `encryptedDbName` / `dbKeyPath`
67
+ - **External RDBMS** — bring-your-own Postgres / MySQL with pool tuning + role-aware connect + read-replica routing (`b.externalDb`); declarative role-narrowed views and Postgres row-level-security migrations (`b.db.declareView`, `b.db.declareRowPolicy`)
68
+ - **Object store** — S3 / R2 / B2 / GCS / Azure with multipart upload + SSE + bucket-ops (create / delete / list / lifecycle / CORS); S3 Object Lock + per-object retention + legal hold for write-once-read-many compliance workloads (`b.storage`, `b.objectStore`)
69
+ - **Queues + cache** — durable queue with priority + cron + flows on local SQLite, shared Redis, OR AWS SQS via SigV4 + AWSJsonProtocol_1.0 (`b.queue`, `b.jobs`); cluster-shared cache (`b.cache`)
70
+ ### Identity & access
71
+
72
+ - **Passwords** — Argon2id + policy primitive (`b.auth.password`); NIST 800-63B / PCI-DSS 4.0 / HIPAA-AAL2 profiles; HaveIBeenPwned k-anonymity breach check; length / context / dictionary / complexity rules; rotation + history
73
+ - **Multi-factor + WebAuthn**passkeys (WebAuthn), TOTP, JWT (PQ-default)
74
+ - **OAuth / OIDC RP** — `b.auth.oauth`
75
+ - RP-Initiated / Front-Channel / Back-Channel Logout 1.0 (`parseFrontchannelLogoutRequest` + `verifyBackchannelLogoutToken` with jti-replay defense)
76
+ - RFC 9207 AS Issuer Identifier validation on callbacks (`parseCallback` — refuses iss mismatch + OP `error=` redirect)
77
+ - OAuth 2.0 JARM signed-response decode (`parseJarmResponse`)
78
+ - One-time-use refresh-token rotation with operator-supplied replay-defense callback (RFC 9700 §4.13 / OAuth 2.1 §6.1 — `refreshAccessToken({ seen })`)
79
+ - **Federation / VC** — CIBA Core 1.0 (`b.auth.ciba`, poll/ping/push); OpenID Federation 1.0 trust chain + metadata_policy (`b.auth.openidFederation`); SAML 2.0 SP with XMLDSig signature-wrapping defense + RFC 9525 server-identity (`b.auth.saml`); OpenID4VCI 1.0 issuer (`b.auth.oid4vci`); OpenID4VP 1.0 verifier with DCQL (`b.auth.oid4vp`); SD-JWT VC with `key_attestation` extension (`b.auth.sdJwtVc`)
80
+ - **Sessions** — `b.session`
81
+ - PQC-sealed sid cookie (ML-KEM-1024 + P-384 hybrid + XChaCha20-Poly1305 wire envelope)
82
+ - `/24` IPv4 + `/64` IPv6 subnet binding via `fingerprintFields: ["clientIpPrefix"]` (carrier-roaming-safe)
83
+ - Pluggable storage via `b.session.useStore` + first-party `b.session.stores.localDbThin` (tmpfs-fast)
84
+ - Opaque-userId anonymous sessions via `create({ anonymous: true })`
85
+ - Idle / absolute timeouts, fingerprint drift detection + anomaly scoring, brute-force lockout
86
+ - **Authorization** — RBAC + per-role DB binding + role-spec `requireMfa` + per-route MFA freshness window + ABAC predicate registry (`b.permissions`); API keys with rotation (`b.apiKey`)
87
+ - **Workflow gates** — break-glass column gates with second-factor + audit (`b.breakGlass`); two-person-rule m-of-n approval with cooling-off lock + cancellation (`b.dualControl`)
88
+ - **Financial / Open Banking** — FAPI 2.0 Final composite posture (PAR + PKCE-S256 + DPoP-or-mTLS + RFC 9207); runtime enforcement helpers `b.fapi2.assertCallback` (refuses missing iss + bare-param under message-signing) and `b.fapi2.assertAuthzRequest` (refuses non-JAR); CFPB §1033 / FDX 6.0 consumer-financial-data-sharing wrapper (`b.fdx`)
89
+ - **Data-subject coordination** — cross-table export / rectify / erase / restrict / objection (`b.subject`, `b.subject.eraseHard`); subject-level legal-hold registry consulted by erase + retention paths (FRCP Rule 26/37(e), GDPR Art 17(3)(e), SEC Rule 17a-4, HIPAA §164.530(j)(2)) (`b.legalHold`)
90
+ - **Account safety** — adaptive bot-challenge staircase (`b.authBotChallenge`); session-to-device-posture binding with fail-closed verify (`b.sessionDeviceBinding`)
91
+ ### Crypto
92
+
93
+ - **At-rest envelope** — envelope-versioned PQC (ML-KEM-1024 + P-384 hybrid, XChaCha20-Poly1305, SHAKE256); vault sealing (`b.crypto`, `b.vault`)
94
+ - **Field-level + crypto-shred** — `b.cryptoField.eraseRow`; per-column data residency tagging + per-row keys (`K_row = HKDF(K_table, rowId)`) so erasing the per-row key makes WAL / replica residuals undecryptable (`b.cryptoField.declareColumnResidency`, `b.cryptoField.declarePerRowKey`)
95
+ - **AAD-bound sealed columns** — AEAD tag tied to `(table, rowId, column, schemaVersion)`; copy-paste between rows or schema-version replay surfaces as refused decrypt (`b.vault.aad`)
96
+ - **Signed webhooks + API encryption** — SLH-DSA-SHAKE-256f default; ML-DSA-65 opt-in; ECIES API encryption (`b.webhook`, `b.crypto`)
97
+ - **HPKE / HTTP signatures** — RFC 9180 HPKE with ML-KEM-1024 + HKDF-SHA3-512 + ChaCha20-Poly1305 (`b.crypto.hpke`); RFC 9421 HTTP Message Signatures with derived components and ed25519 / ML-DSA-65 (`b.crypto.httpSig`)
98
+ - **TLS / channel binding** — RFC 9266 TLS-Exporter token-to-session pinning (`b.tlsExporter`); RFC 9162 CT v2 inclusion-proof verification (`b.network.tls.ct.verifyInclusion`); RFC 8555 ACME + RFC 9773 ARI for 47-day certs (`b.acme`); RFC 8470 0-RTT inbound posture refuse / replay-cache (`b.router.create({tls0Rtt})`); RFC 9794 SecP256r1MLKEM768 in preferred-group order (`b.network.tls.preferredGroups`)
99
+ - **mTLS CA** — pure-JS, issues clientAuth / serverAuth / dual-EKU certs with SAN; auto-detects highest-PQC signature alg (today ECDSA-P384-SHA384; self-upgrades to SLH-DSA / ML-DSA when X.509 ecosystem catches up); PQC TLS gates inbound + outbound (`b.mtlsCa`, `b.pqcGate`, `b.pqcAgent`)
100
+ ### HTTP
101
+
102
+ - **Router + API specs** — schema-validated routes; OpenAPI publication (`b.openapi`) + AsyncAPI publication for event/streaming (`b.asyncapi`)
103
+ - **Middleware stack (wired by `createApp`)**
104
+ - CSRF protection
105
+ - CORS with W3C Private Network Access preflight refusal default + `allowPrivateNetwork` opt
106
+ - Rate-limit
107
+ - Security headers with `Permissions-Policy` defaults denying storage-access / browsing-topics / private-aggregation / controlled-frame
108
+ - CSP nonce
109
+ - Body parser
110
+ - Compression
111
+ - SSE
112
+ - Request log
113
+ - Threat-aware cookie parser (`b.middleware.cookies`)
114
+ - Request-time DB role binding (`b.middleware.dbRoleFor`)
115
+ - In-process CIDR fence (`b.middleware.networkAllowlist`)
116
+ - `Cache-Control: no-store` on every 401 from `requireAuth` / `requireAal` / `requireStepUp` per RFC 9111 §5.2.2.5
117
+ - **Outbound HTTP client** — HTTP/1.1 + HTTP/2 with SSRF gate (cloud-metadata IPs hard-denied; private / loopback / link-local overridable per call); scheme + userinfo + per-host destination allowlist; redirects, multipart, interceptors, progress, encrypted cookie jar (`b.httpClient`, `b.ssrfGuard`, `b.safeUrl`)
118
+ - **Network configurability (`b.network`)** — env-driven NTP / NTS (RFC 8915), IPv4/IPv6 NTP, DNS with IPv6 / DoH / DoT (private-CA pinning) / cache / lookup timeout; outbound HTTP proxy (`HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`); runtime DPI trust-store CA additions; application-level heartbeats; TCP socket defaults
119
+ - **Error pages** — operator-rendered, no app-frame leakage (`b.errorPage`)
120
+ ### Defensive parsers
121
+
122
+ - **JSON / SQL / schema** — `b.safeJson` (with `maxKeys` cap defending CVE-2026-21717 V8 HashDoS), `b.safeBuffer`, `b.safeSql`, `b.safeSchema`
123
+ - **URL + path** — `b.safeUrl` (IDN mixed-script / homograph refuse); `b.safeJsonPath` (refuses filter `?(...)`, deep-scan `$..`, script-shape `(@.x)` for safe Postgres JSONB ops)
124
+ - **Document parsers** — `b.parsers` (XML / TOML / YAML / .env); `b.config` (schema-validated env)
125
+ - **File-type detection** — `b.fileType` magic-byte content classification with deny-on-upload categories (image / document / archive / executable / etc.)
126
+ ### Content-safety gates
127
+
128
+ - **Composition contract** — `b.gateContract` uniform mode posture / hooks / forensic snapshot / decision cache / runtime cap
129
+ - **Document guards** — `b.guardCsv` (formula injection, dangerous-function denylist, bidi / homoglyph / dialect ambiguity, CSV-bombs); `b.guardHtml` (XSS / mXSS / DOM-clobbering, dangerous-tag + event-handler family, URL-scheme with entity-decode bypass, CSS-injection in style); `b.guardSvg` (script / foreignObject / animation href hijack / DOCTYPE / XXE / SVGZ / cross-origin `<use>` SSRF); `b.guardMarkdown` (URL schemes pre-render, CVE-2026-30838 dangerous-tag, ReDoS emphasis runs)
130
+ - **Structured data** — `b.guardJson` (prototype-pollution, dup keys, JSON5, depth/breadth caps); `b.guardYaml` (deserialization-tag RCE, billion-laughs aliases, Norway-problem); `b.guardXml` (XXE / billion-laughs / xi:include / signature wrapping; DOCTYPE refused at all profile levels)
131
+ - **Archive + filename** — `b.guardArchive` (zip-slip, symlink + hardlink escape, decompression bombs, duplicate-entry); `b.guardFilename` (path traversal raw + percent-encoded + overlong-UTF-8, null-byte, Windows reserved, NTFS ADS, RTLO bidi)
132
+ - **Email** — `b.guardEmail` (SMTP smuggling per CVE-2023-51764 / 51765 / 51766 class, CRLF header injection, IDN homograph, IP-literals, RFC 5321 length caps)
133
+ - **Profiles + postures** — every member ships strict / balanced / permissive plus hipaa / pci-dss / gdpr / soc2
134
+ - **Aggregator** — `b.guardAll` registry; every shipped guard ON by default; opt-out per guard with audited reason via `exceptFor: { name: { reason } }`. `b.fileUpload` and `b.staticServe` wire `b.guardAll.byExtension({ profile: "strict" })` + `b.guardFilename.gate({ profile: "strict" })` automatically — operator opts out via `contentSafety: null` / `filenameSafety: null` (audited)
135
+ ### Communication
136
+
137
+ - **WebSockets (server)** — channel/room fan-out across cluster replicas; RFC 6455 §5.5 control-frame size + FIN enforcement on inbound (defends 1 MiB-PING-as-PONG amplification) (`b.websocket`, `b.websocketChannels`)
138
+ - **WebSockets (client)** — `b.wsClient` with PQC-TLS handshake, permessage-deflate negotiation with decompression-bomb cap, fatal UTF-8 validation, permanent-error classifier (skips reconnect on 4xx / accept mismatch / bad-subprotocol), exponential-backoff with full jitter
139
+ - **Pub/sub + events** — distributed pub/sub with cluster-table / Redis PUB/SUB / custom backends (`b.pubsub`); framework-emitted signal bus for breach / integrity events (`b.events`)
140
+ - **CloudEvents + SSE** — CloudEvents 1.0 envelope for AWS EventBridge / Knative / Azure Event Grid / Google Eventarc / CNCF (`b.cloudEvents`); Server-Sent Events with newline-injection refusal in `event:` / `id:` / `data:` / `Last-Event-ID` (CVE-2026-33128 / 29085 / 44217 class) (`b.sse`, `b.middleware.sse`)
141
+ - **Mail (outbound)** — multipart + attachments + DKIM + calendar invites; bounce intake (`b.mail`, `b.mailBounce`)
142
+ - **Mail (inbound auth)** — SPF / DMARC / ARC verify + ARC chain signing for relays (`b.mail.spf`, `b.mail.dmarc`, `b.mail.arc`)
143
+ - **Notifications** — generic dispatcher with operator-supplied transports (`b.notify`); TCPA / FCC 1:1 prior-express-written-consent + 10DLC carrier-shaped consent snapshot for SMS marketing (`b.tcpa10dlc`)
144
+ - **File uploads** — chunked with per-chunk SHA3-512 verification + atomic finalize + tombstone cleanup (`b.fileUpload`)
145
+ ### AI / agentic
146
+
147
+ - **MCP (Model Context Protocol)** — `b.mcp.serverGuard` with bearer auth + redirect_uri allowlist + dynamic-register refusal + tool/resource allowlists (CVE-2026-33032 / CVE-2025-6514 / confused-deputy class)
148
+ - **MCP safety primitives**
149
+ - `b.mcp.toolResult.sanitize` — prompt-injection / dangerous-HTML / off-allowlist-URL detection (OWASP LLM07)
150
+ - `b.mcp.capability.create` — least-privilege capability scopes (OWASP LLM08)
151
+ - `b.mcp.validateToolInput` — JSON Schema 2020-12 input enforcement
152
+ - **GraphQL Federation** — `_service.sdl` trust-boundary with router-token + nonce store (`b.graphqlFederation`)
153
+ - **Prompt-injection classification** — OWASP LLM01:2025 / NIST COSAIS RFI (`b.ai.input.classify`)
154
+ - **Agent identity** — A2A signed agent-card primitive (Linux Foundation Agentic AI Foundation v1.x, ML-DSA-87) (`b.a2a`)
155
+ - **Content provenance** — C2PA 2.1 + California SB-942 / AB-853 manifest builder for AI-generated media (provider, model id + version, timestamp, content ID, signed) (`b.contentCredentials`)
156
+ ### Compliance regimes
157
+
158
+ - **Posture coordinator** — `b.compliance` cascades operator-declared regime into retention / audit / db / cryptoField via POSTURE_DEFAULTS:
159
+ - **US** — `hipaa` / `hipaa-2026` / `pci-dss` / `sox-404` / `soc2` / `soc2-cc1.3` / `sec-cyber` / `sec-17a-4` / `finra-4511` / `fda-21cfr11` / `fda-annex-11` / `modpa` / `nydfs-500` / `staterramp`
160
+ - **EU / UK** — `gdpr` / `dora` / `nis2` / `cra` / `uk-g-cloud`
161
+ - **APAC + LATAM** — `dpdp` / `pipl-cn` / `lgpd-br` / `appi-jp` / `pdpa-sg` / `quebec-25` / `irap`
162
+ - **Financial / data-portability** — `fapi2` / `fapi-2.0-message-signing` / `fdx` / `dsr`
163
+ - **Other** — `bsi-c5` / `ens-es` / etc.
164
+ - **EU Data Act** — Regulation 2023/2854 connected-product data access workflow with DMA-gatekeeper share refusal (Art 32 §1) and 30-day switch-request notice cap (Art 28 §3) (`b.dataAct`)
165
+ - **Audit + segregation** — 21 CFR Part 11 §11.10(e) audit-content gate + §11.50(b) electronicSignature (`b.fda21cfr11`); PCI DSS 4.0 Req 10.4.1.1 daily-review automation (`b.auditDailyReview`); SOX §404 + SOC 2 CC1.3 segregation-of-duties via Postgres trigger DDL (`b.audit.bindActor`, `b.audit.assertSegregation`)
166
+ - **Change control + WORM** — m-of-n approver DDL change-control with maintenance-window + ML-DSA-87 signed proposals (`b.ddlChangeControl`); row-level WORM triggers boot-asserted under `sec-17a-4` / `finra-4511` / `fda-21cfr11` (`b.db.declareWorm`); dual-control physical delete + crypto-erase + REINDEX in one transaction (`b.db.declareRequireDualControl`, `b.db.eraseHard`)
167
+ - **Consumer-protection** — FTC click-to-cancel UX-parity attestation (`ftc-2024` / `ca-sb942` / `strict`) (`b.darkPatterns`)
168
+ - **Privacy / DSR** — GDPR Articles 15–22 / CCPA / CPRA / LGPD / PIPEDA data-subject-rights workflow (`b.dsr`); IAB TCF v2.3 consent-string parser + `disclosedVendors` validator (`b.iabTcf`); IAB MSPA / GPP universal-opt-out (USNAT / USCA / USVA / USCO / USCT / USUT) + GPC mirror (`b.iabMspa`); generic consent capture + withdrawal (`b.consent`)
169
+ - **Incident reporters** — EU DORA Article 17 ICT-incident workflow per Commission Delegated Regulation 2024/1772 (`b.dora`); EU NIS2 (`b.nis2`); EU Cyber Resilience Act SBOM + secure-software-attestation (`b.cra`); SEC Form 8-K Item 1.05 cybersecurity-incident materiality-disclosure (`b.secCyber`); incident lifecycle coordinator (`b.incident`)
170
+ - **Outbound DLP** — interceptor-installed on httpClient + mail + webhook with built-in detectors for PAN (Luhn), SSN, EIN, IBAN (mod-97), api-key shapes, PEM, SSH private keys, JWTs, AWS access keys, PHI composite; refuse / redact / audit-only verdicts under pci-dss / hipaa / fapi2 / soc2 / gdpr presets (`b.redact.installOutboundDlp`)
171
+ ### Observability
172
+
173
+ - **Audit chain** — tamper-evident, SLH-DSA-signed checkpoints; CADF (ISO/IEC 19395:2017) envelope export for federated SIEM (`b.audit`, `b.audit.export({ format: "cadf" })`)
174
+ - **Metrics + tracing** — `b.metrics`, `b.tracing` (OTel pass-through); OTLP/HTTP-JSON exporter for traces + metrics (`b.otelExport`)
175
+ - **Log-stream sinks** — local file rotation, generic webhook, OTLP/HTTP-JSON OR OTLP/gRPC, AWS CloudWatch Logs via SigV4 with optional autoCreate, RFC 5424 syslog over UDP/TCP/TLS (`b.logStream`)
176
+ - **PII redaction** — `b.redact`
177
+ - **Decoy detection** — canary-credential / decoy-record framework auditing every positive lookup as `honeytoken.tripped` (`b.honeytoken`)
178
+ - **Boot assertions** — operator-callable security policy assertions (`b.security.assertProduction`); tamper-evident config-baseline drift detection signed with audit-signing key + at-boot vendor-bundle SHA-256 integrity verification across `lib/vendor/*` (`b.configDrift`, `b.configDrift.verifyVendorIntegrity`)
179
+ - **CSP reports + forensic export** — `b.middleware.cspReport`; post-incident audit-bundle composer (`b.auditTools.forensicSnapshot`)
180
+
181
+ ### i18n + format helpers
182
+
183
+ - **i18n** — CLDR plural rules, Accept-Language negotiation, Intl formatters, RTL (`b.i18n`)
184
+ - **CSV** — RFC 4180 with Excel formula-injection prevention (`b.csv`)
185
+ - **IDs + slugs** — RFC 9562 UUID v4 + v7 (`b.uuid`); URL-safe slugs (`b.slug`)
186
+ - **Time + archive** — TZ-aware datetime (`b.time`); ZIP creation (`b.archive`)
187
+ - **Pagination + forms** — HMAC-signed cursor pagination (`b.pagination`); HTML form rendering + validation + CSRF (`b.forms`)
188
+
189
+ ### Production
190
+
191
+ - **Cluster + scheduling** — cluster leader election with fenced leases over Postgres/SQLite (`b.cluster`); cron + interval scheduler that runs exactly-once globally (`b.scheduler`)
192
+ - **Reliability** — retry with full-jitter backoff + circuit breaker (`b.retry`); graceful shutdown (`b.appShutdown`); NTP boot check (`b.ntpCheck`)
193
+ - **Transactional integration** — outbox + dedupe-on-receive inbox; exactly-once semantics across Postgres / SQLite (`b.outbox`, `b.inbox`); Debezium-shape change-event envelope on the outbox (`b.outbox.create({ envelope: "debezium" })`)
194
+ - **Backup + restore** — end-to-end-encrypted bundles with pre-flush fail-closed mode + ML-DSA-87 signed manifests + scheduled backup-restore drills (`b.backup`, `b.backup.scheduleTest`, `b.backupBundle.verifyManifestSignature`); restore with pulled-bundle footprint preflight (`b.restore`); disaster-recovery runbook generator (HIPAA / PCI-DSS / GDPR / SOC 2 / DORA postures) (`b.drRunbook`)
195
+ - **Multi-tenant** — per-tenant DB storage caps, query budgets, tenant-isolation breach detection (`b.tenantQuota`); per-Postgres-role hardening with `pg_roles` enumeration guard (`b.externalDb.assertRoleHardening`)
196
+ - **Data export** — RFC 4180 strict CSV table export with SHA3-512 manifest + ML-DSA-87 signature + JSON Schema 2020-12 reflective metadata (`b.db.exportCsv`, `b.db.getTableMetadata`)
197
+ - **Retention** — GDPR / PCI / HIPAA-shaped rules with multi-stage warn → archive → erase, legal-hold exemptions, dry-run preview, cross-table cascade (`b.retention`)
198
+ - **Feature flags** — OpenFeature-spec client with pluggable providers + evaluation-context targeting + per-request `req.flag` accessor (`b.flag`)
199
+ - **Concurrency + kill-switches** — per-resource lock with cooperative-cancel + audit (`b.resourceAccessLock`); composite account-takeover kill-switch (`b.atoKillSwitch`)
200
+ - **Sandbox + spawn** — `worker_threads` sandbox with strict resource limits (`b.sandbox`, composable into `b.template.create({ sandbox: true })`); hardened `processSpawn` refusing shell-string invocation (`b.processSpawn`)
201
+ - **Egress allowlist** — per-host outbound destination allowlist (wildcard / per-method) via `b.httpClient.request({ allowedHosts: [...] })`
57
202
 
58
203
  ## Documentation
59
204
 
package/index.js CHANGED
@@ -141,6 +141,7 @@ var ddlChangeControl = require("./lib/ddl-change-control");
141
141
  var compliance = Object.assign({}, require("./lib/compliance"), {
142
142
  eaa: require("./lib/compliance-eaa"),
143
143
  });
144
+ var dataAct = require("./lib/data-act");
144
145
  var gateContract = require("./lib/gate-contract");
145
146
  var guardCsv = require("./lib/guard-csv");
146
147
  var guardHtml = require("./lib/guard-html");
@@ -366,6 +367,7 @@ module.exports = {
366
367
  auditDailyReview: auditDailyReview,
367
368
  ddlChangeControl: ddlChangeControl,
368
369
  compliance: compliance,
370
+ dataAct: dataAct,
369
371
  gateContract: gateContract,
370
372
  guardCsv: guardCsv,
371
373
  guardHtml: guardHtml,
package/lib/audit.js CHANGED
@@ -293,6 +293,7 @@ var FRAMEWORK_NAMESPACES = [
293
293
  "mailarf", // b.mailArf (mailarf.parsed / mailarf.malformed — RFC 5965 abuse-feedback ingestion)
294
294
  "mailbimi", // b.mail.bimi (mail.bimi.vmc.fetched / verified — RFC 9091 VMC chain validation)
295
295
  "localdb", // b.localDb.thin (localdb.thin.opened / recovered / closed — desktop-daemon SQLite wrapper)
296
+ "dataact", // b.dataAct (EU Data Act 2023/2854 — product_declared / user_access / share_with_third_party / share_refused / switch_request)
296
297
  ];
297
298
  var registeredNamespaces = new Set(FRAMEWORK_NAMESPACES);
298
299
 
package/lib/auth/oauth.js CHANGED
@@ -543,11 +543,35 @@ function create(opts) {
543
543
  return await _normalizeTokens(tokens, { nonce: eopts.nonce, skipNonceCheck: eopts.skipNonceCheck });
544
544
  }
545
545
 
546
- async function refreshAccessToken(refreshToken) {
546
+ async function refreshAccessToken(refreshToken, ropts) {
547
+ ropts = ropts || {};
547
548
  if (!refreshToken) {
548
549
  throw new OAuthError("auth-oauth/no-refresh-token",
549
550
  "refreshAccessToken: refresh token is required");
550
551
  }
552
+ // OAuth 2.1 §6.1 / RFC 9700 §4.13 — refresh-token replay defense.
553
+ // Operator passes a `seen(refreshToken)` callback that returns
554
+ // truthy when the SAME refresh_token has been presented before.
555
+ // The framework refuses the request loudly because OAuth 2.1
556
+ // mandates one-time-use refresh tokens for public + non-sender-
557
+ // constrained confidential clients. Operators with sender-
558
+ // constrained tokens (DPoP / mTLS) can opt out by NOT supplying
559
+ // a seen callback.
560
+ if (typeof ropts.seen === "function") {
561
+ var alreadySeen;
562
+ try { alreadySeen = await ropts.seen(refreshToken); }
563
+ catch (e) {
564
+ throw new OAuthError("auth-oauth/seen-callback-failed",
565
+ "refreshAccessToken: seen() callback threw: " + ((e && e.message) || String(e)));
566
+ }
567
+ if (alreadySeen === true) {
568
+ throw new OAuthError("auth-oauth/refresh-token-replay",
569
+ "refreshAccessToken: refresh token has been presented before — refused " +
570
+ "(OAuth 2.1 §6.1 / RFC 9700 §4.13 one-time-use defense). The operator MUST " +
571
+ "treat this as a token-theft signal: revoke the refresh-token family + force " +
572
+ "the user to re-authenticate.");
573
+ }
574
+ }
551
575
  var endpoint = await _resolveEndpoint("tokenEndpoint");
552
576
  var body = new URLSearchParams();
553
577
  body.set("grant_type", "refresh_token");
@@ -556,8 +580,181 @@ function create(opts) {
556
580
  if (clientSecret) body.set("client_secret", clientSecret);
557
581
  var tokens = await _postForm(endpoint, body);
558
582
  // Refreshed tokens may not include a new id_token; verification
559
- // is conditional.
560
- return await _normalizeTokens(tokens, { skipNonceCheck: true });
583
+ // is conditional. We surface rotation explicitly so the operator's
584
+ // store can swap the old refresh_token for the new one and feed
585
+ // the new one to the next seen() check.
586
+ var normalized = await _normalizeTokens(tokens, { skipNonceCheck: true });
587
+ if (normalized.refreshToken && normalized.refreshToken !== refreshToken) {
588
+ normalized.refreshTokenRotated = true;
589
+ normalized.previousRefreshToken = refreshToken;
590
+ } else {
591
+ normalized.refreshTokenRotated = false;
592
+ }
593
+ return normalized;
594
+ }
595
+
596
+ /**
597
+ * @primitive b.auth.oauth.parseCallback
598
+ * @signature b.auth.oauth.parseCallback(query, opts?)
599
+ * @since 0.8.70
600
+ * @related b.auth.oauth.parseJarmResponse, b.fapi2.assertCallback
601
+ *
602
+ * Parses the OP's redirect-back query/form parameters and applies
603
+ * RFC 9207 OAuth 2.0 Authorization Server Issuer Identification
604
+ * cross-checks. The `iss` parameter the OP echoes on the callback
605
+ * MUST match the configured issuer; mismatches surface as a
606
+ * deterministic refusal (mix-up / IdP-substitution defense per
607
+ * RFC 9207 §2.3).
608
+ *
609
+ * The framework refuses the callback when:
610
+ * - an `error` param is present (OP-side authorization failure)
611
+ * - `iss` is present but does NOT match the configured issuer
612
+ * - `state` is supplied to opts.expectedState and doesn't match
613
+ *
614
+ * Returns `{ code, state, iss }` for the happy path. Operators feed
615
+ * `code` + their stored `verifier` + `nonce` to `exchangeCode`.
616
+ *
617
+ * The OP advertises support via `authorization_response_iss_parameter_supported`
618
+ * in discovery; the framework reads it once at the first parseCallback
619
+ * call and refuses missing-`iss` callbacks under FAPI 2.0 posture
620
+ * regardless (per FAPI 2.0 §5.4.2).
621
+ *
622
+ * @opts
623
+ * {
624
+ * expectedState?: string, // value returned by authorizationUrl()
625
+ * requireIssParam?: boolean, // refuse callbacks lacking iss (default: read OP discovery; FAPI 2.0 forces true)
626
+ * }
627
+ *
628
+ * @example
629
+ * app.get("/oauth/callback", async function (req, res) {
630
+ * var url = new URL(req.url, "http://placeholder.invalid");
631
+ * var params = Object.fromEntries(url.searchParams);
632
+ * var parsed = await oauth.parseCallback(params, { expectedState: req.session.oauthState });
633
+ * var tokens = await oauth.exchangeCode({ code: parsed.code,
634
+ * verifier: req.session.pkceVerifier, nonce: req.session.oidcNonce });
635
+ * });
636
+ */
637
+ async function parseCallback(query, popts) {
638
+ popts = popts || {};
639
+ if (!query || typeof query !== "object") {
640
+ throw new OAuthError("auth-oauth/bad-callback",
641
+ "parseCallback: query must be an object of param key→value");
642
+ }
643
+ if (typeof query.error === "string" && query.error.length > 0) {
644
+ var aerr = new OAuthError("auth-oauth/op-error",
645
+ "parseCallback: OP returned error '" + query.error + "'" +
646
+ (query.error_description ? ": " + query.error_description : ""));
647
+ aerr.opError = query.error;
648
+ aerr.opErrorDescription = query.error_description || null;
649
+ throw aerr;
650
+ }
651
+ // RFC 9207 — when the OP echoes `iss`, cross-check it against the
652
+ // configured issuer. Defends against the mix-up attack where an
653
+ // honest-but-curious OP receives a code intended for a different
654
+ // OP. The cross-check is critical for OPs with multi-tenant
655
+ // shared clients.
656
+ var requireIss = popts.requireIssParam === true;
657
+ if (!requireIss) {
658
+ // OP discovery may advertise support; check once.
659
+ var disc = null;
660
+ try { disc = await _discover(); } catch (_e) { /* discovery already failed elsewhere; let exchangeCode surface it */ }
661
+ if (disc && disc.authorization_response_iss_parameter_supported === true) {
662
+ requireIss = true;
663
+ }
664
+ }
665
+ if (typeof query.iss === "string" && query.iss.length > 0) {
666
+ if (query.iss !== issuer) {
667
+ throw new OAuthError("auth-oauth/iss-mismatch-callback",
668
+ "parseCallback: callback iss '" + query.iss + "' does not match " +
669
+ "configured issuer '" + issuer + "' (RFC 9207 §2.3 mix-up defense)");
670
+ }
671
+ } else if (requireIss) {
672
+ throw new OAuthError("auth-oauth/missing-iss-callback",
673
+ "parseCallback: OP advertises authorization_response_iss_parameter_supported " +
674
+ "but the callback omitted `iss` — refused (RFC 9207 / FAPI 2.0 §5.4.2)");
675
+ }
676
+ if (popts.expectedState !== undefined && popts.expectedState !== null) {
677
+ if (query.state !== popts.expectedState) {
678
+ throw new OAuthError("auth-oauth/state-mismatch",
679
+ "parseCallback: state mismatch (CSRF defense). Expected '" +
680
+ popts.expectedState + "', got '" + query.state + "'");
681
+ }
682
+ }
683
+ if (typeof query.code !== "string" || query.code.length === 0) {
684
+ throw new OAuthError("auth-oauth/no-code-in-callback",
685
+ "parseCallback: callback missing `code` parameter");
686
+ }
687
+ return { code: query.code, state: query.state || null, iss: query.iss || issuer };
688
+ }
689
+
690
+ /**
691
+ * @primitive b.auth.oauth.parseJarmResponse
692
+ * @signature b.auth.oauth.parseJarmResponse(responseJwt, opts?)
693
+ * @since 0.8.70
694
+ * @related b.auth.oauth.parseCallback, b.fapi2.assertCallback
695
+ *
696
+ * JWT Authorization Response Mode (JARM, OAuth 2.0 JARM spec).
697
+ * When `response_mode` is `query.jwt` / `fragment.jwt` /
698
+ * `form_post.jwt`, the OP delivers the authorization response as a
699
+ * signed JWT in a single `response` parameter instead of as bare
700
+ * query/form params. This primitive verifies the JWS against the
701
+ * OP's JWKS, validates `iss` / `aud` / `exp` / `nbf`, and returns
702
+ * the inner params (`code` / `state` / `iss` / `error`) as if they
703
+ * had been the raw query.
704
+ *
705
+ * The verified params then flow through `parseCallback` for the
706
+ * normal RFC 9207 + state-CSRF + error-refusal pipeline.
707
+ *
708
+ * @opts
709
+ * {
710
+ * expectedState?: string,
711
+ * acceptedAlgs?: string[], // default: framework's accepted set
712
+ * maxClockSkewMs?: number,
713
+ * }
714
+ *
715
+ * @example
716
+ * app.get("/oauth/callback", async function (req, res) {
717
+ * var jwt = new URL(req.url, "x:/").searchParams.get("response");
718
+ * var params = await oauth.parseJarmResponse(jwt, { expectedState: req.session.oauthState });
719
+ * var tokens = await oauth.exchangeCode({ code: params.code,
720
+ * verifier: req.session.pkceVerifier, nonce: req.session.oidcNonce });
721
+ * });
722
+ */
723
+ async function parseJarmResponse(responseJwt, jopts) {
724
+ jopts = jopts || {};
725
+ if (typeof responseJwt !== "string" || responseJwt.length === 0) {
726
+ throw new OAuthError("auth-oauth/no-jarm-response",
727
+ "parseJarmResponse: response JWT required");
728
+ }
729
+ if (responseJwt.split(".").length !== 3) {
730
+ throw new OAuthError("auth-oauth/malformed-jarm-response",
731
+ "parseJarmResponse: response is not a 3-segment JWS");
732
+ }
733
+ // Reuse verifyIdToken's JWKS-lookup + signature path. JARM
734
+ // responses share the OP's signing keypair; the checks differ
735
+ // only in claim validation (no nonce, audience = clientId, no
736
+ // ID-token-specific claims). We wrap verifyIdToken with the
737
+ // skip-nonce flag and apply JARM-specific claim checks below.
738
+ var verified = await verifyIdToken(responseJwt, {
739
+ skipNonceCheck: true,
740
+ acceptedAlgs: jopts.acceptedAlgs,
741
+ maxClockSkewMs: jopts.maxClockSkewMs,
742
+ });
743
+ var c = verified.claims;
744
+ // Per JARM §4: `iss` MUST match the OP issuer; `aud` MUST contain
745
+ // the client_id; `exp` enforced (verifyIdToken already does);
746
+ // `nonce` MUST NOT be present (JARM responses are not ID tokens).
747
+ if (Object.prototype.hasOwnProperty.call(c, "nonce")) {
748
+ throw new OAuthError("auth-oauth/jarm-forbidden-nonce",
749
+ "parseJarmResponse: JARM responses MUST NOT carry `nonce` (JARM §4)");
750
+ }
751
+ return await parseCallback({
752
+ code: c.code,
753
+ state: c.state,
754
+ iss: c.iss,
755
+ error: c.error,
756
+ error_description: c.error_description,
757
+ }, { expectedState: jopts.expectedState, requireIssParam: jopts.requireIssParam });
561
758
  }
562
759
 
563
760
  // OIDC requires fetchUserInfo to be called AFTER the id_token has
@@ -1068,6 +1265,8 @@ function create(opts) {
1068
1265
  parseFrontchannelLogoutRequest: parseFrontchannelLogoutRequest,
1069
1266
  verifyBackchannelLogoutToken: verifyBackchannelLogoutToken,
1070
1267
  checkSessionIframeUrl: checkSessionIframeUrl,
1268
+ parseCallback: parseCallback,
1269
+ parseJarmResponse: parseJarmResponse,
1071
1270
  // Diagnostic / power-user surface
1072
1271
  issuer: issuer,
1073
1272
  clientId: clientId,