@blamejs/core 0.9.14 → 0.9.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/a2a-tasks.js +2 -2
  3. package/lib/a2a.js +11 -11
  4. package/lib/acme.js +5 -5
  5. package/lib/ai-input.js +2 -2
  6. package/lib/api-key.js +4 -4
  7. package/lib/api-snapshot.js +6 -6
  8. package/lib/app-shutdown.js +2 -2
  9. package/lib/app.js +5 -5
  10. package/lib/archive.js +8 -8
  11. package/lib/argon2-builtin.js +2 -2
  12. package/lib/atomic-file.js +53 -53
  13. package/lib/audit-sign.js +8 -8
  14. package/lib/audit-tools.js +22 -22
  15. package/lib/auth/dpop.js +3 -3
  16. package/lib/auth/elevation-grant.js +3 -3
  17. package/lib/auth/fido-mds3.js +6 -6
  18. package/lib/auth/jwt-external.js +2 -2
  19. package/lib/auth/sd-jwt-vc.js +2 -2
  20. package/lib/backup/bundle.js +17 -17
  21. package/lib/backup/index.js +36 -36
  22. package/lib/budr.js +3 -3
  23. package/lib/bundler.js +20 -20
  24. package/lib/circuit-breaker.js +4 -4
  25. package/lib/cli.js +25 -26
  26. package/lib/cluster.js +2 -2
  27. package/lib/compliance-sanctions.js +2 -2
  28. package/lib/compliance.js +6 -7
  29. package/lib/config-drift.js +15 -15
  30. package/lib/config.js +6 -6
  31. package/lib/content-credentials.js +4 -4
  32. package/lib/credential-hash.js +7 -7
  33. package/lib/crypto-field.js +9 -9
  34. package/lib/daemon.js +19 -19
  35. package/lib/db-file-lifecycle.js +24 -24
  36. package/lib/db-schema.js +2 -2
  37. package/lib/db.js +34 -34
  38. package/lib/dev.js +10 -10
  39. package/lib/dr-runbook.js +5 -5
  40. package/lib/dual-control.js +2 -2
  41. package/lib/external-db-migrate.js +17 -17
  42. package/lib/external-db.js +2 -2
  43. package/lib/fdx.js +2 -2
  44. package/lib/file-upload.js +30 -30
  45. package/lib/flag-evaluation-context.js +2 -2
  46. package/lib/flag-providers.js +4 -4
  47. package/lib/gate-contract.js +5 -5
  48. package/lib/graphql-federation.js +4 -7
  49. package/lib/honeytoken.js +6 -6
  50. package/lib/http-client-cookie-jar.js +6 -6
  51. package/lib/http-client.js +18 -18
  52. package/lib/i18n.js +5 -5
  53. package/lib/keychain.js +5 -5
  54. package/lib/legal-hold.js +2 -2
  55. package/lib/local-db-thin.js +9 -9
  56. package/lib/log-stream-local.js +17 -17
  57. package/lib/log-stream-syslog.js +2 -2
  58. package/lib/log-stream.js +3 -3
  59. package/lib/log.js +2 -2
  60. package/lib/mail-bounce.js +2 -2
  61. package/lib/mail-mdn.js +2 -2
  62. package/lib/mail-srs.js +2 -2
  63. package/lib/mail.js +7 -7
  64. package/lib/mcp-tool-registry.js +6 -6
  65. package/lib/mcp.js +2 -2
  66. package/lib/metrics.js +2 -2
  67. package/lib/middleware/api-encrypt.js +16 -16
  68. package/lib/middleware/body-parser.js +18 -18
  69. package/lib/middleware/compression.js +3 -3
  70. package/lib/middleware/csp-nonce.js +4 -4
  71. package/lib/middleware/health.js +7 -7
  72. package/lib/middleware/idempotency-key.js +163 -63
  73. package/lib/middleware/require-bound-key.js +4 -4
  74. package/lib/middleware/require-mtls.js +4 -4
  75. package/lib/migrations.js +5 -5
  76. package/lib/mtls-ca.js +26 -26
  77. package/lib/mtls-engine-default.js +5 -5
  78. package/lib/network-byte-quota.js +2 -2
  79. package/lib/network-dns.js +2 -2
  80. package/lib/network-nts.js +2 -2
  81. package/lib/network-proxy.js +3 -3
  82. package/lib/network-smtp-policy.js +2 -2
  83. package/lib/network-tls.js +17 -17
  84. package/lib/network.js +25 -25
  85. package/lib/notify.js +11 -11
  86. package/lib/object-store/gcs-bucket-ops.js +2 -2
  87. package/lib/object-store/gcs.js +5 -5
  88. package/lib/object-store/index.js +6 -6
  89. package/lib/object-store/local.js +19 -19
  90. package/lib/object-store/sigv4.js +3 -3
  91. package/lib/observability-tracer.js +4 -4
  92. package/lib/otel-export.js +3 -3
  93. package/lib/pagination.js +5 -5
  94. package/lib/parsers/safe-env.js +3 -3
  95. package/lib/parsers/safe-xml.js +3 -3
  96. package/lib/pqc-gate.js +5 -5
  97. package/lib/pubsub-redis.js +2 -2
  98. package/lib/queue-local.js +3 -3
  99. package/lib/queue.js +2 -2
  100. package/lib/redis-client.js +4 -4
  101. package/lib/restore-bundle.js +17 -17
  102. package/lib/restore-rollback.js +34 -34
  103. package/lib/restore.js +16 -16
  104. package/lib/router.js +25 -25
  105. package/lib/sandbox.js +8 -8
  106. package/lib/sec-cyber.js +3 -3
  107. package/lib/security-assert.js +2 -2
  108. package/lib/seeders.js +6 -6
  109. package/lib/self-update.js +18 -18
  110. package/lib/session-device-binding.js +2 -2
  111. package/lib/static.js +22 -22
  112. package/lib/template.js +19 -19
  113. package/lib/testing.js +9 -9
  114. package/lib/tls-exporter.js +5 -5
  115. package/lib/tracing.js +3 -3
  116. package/lib/vault/index.js +11 -11
  117. package/lib/vault/passphrase-ops.js +37 -37
  118. package/lib/vault/passphrase-source.js +2 -2
  119. package/lib/vault/rotate.js +64 -64
  120. package/lib/vault/seal-pem-file.js +26 -26
  121. package/lib/vault-aad.js +5 -5
  122. package/lib/watcher.js +22 -22
  123. package/lib/webhook.js +10 -10
  124. package/lib/worker-pool.js +6 -6
  125. package/lib/ws-client.js +6 -6
  126. package/package.json +1 -1
  127. package/sbom.cdx.json +6 -6
package/CHANGELOG.md CHANGED
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
8
8
 
9
9
  ## v0.9.x
10
10
 
11
+ - v0.9.16 (2026-05-14) — **Operator-facing prose cleanup + `require-binding-name` detector now covers `lazyRequire` wrappers + dbStore seal round-trip test added.** Post-v0.9.15 audit surfaced three classes of follow-up. (1) **Operator-facing prose leaks (7 sites)** — the v0.9.15 mechanical rename pattern `<OLD>.` → `<NEW>.` also caught occurrences inside JSDoc `@opts` comments and error-message string literals, so operators reading `b.keychain.create(opts)` saw `// absolute nodePath; required if file fallback may engage` instead of `// absolute path`. Fixed: `lib/db.js` (stream-limit error), `lib/keychain.js` (fallback-file error + 3 JSDoc lines), `lib/restore-bundle.js` (staging-dir error), `lib/watcher.js` (fs.watch failure error). Operators see plain English; internal binding names stay internal. (2) **`require-binding-name` detector extended to cover `lazyRequire`** — the v0.9.15 detector only matched plain `var X = require("M")` and missed the framework's `var X = lazyRequire(function () { return require("M"); })` pattern (used to break load cycles). 34 additional inconsistencies surfaced (`auditFwk` / `auditMod` / `auditModule` / `lazyAudit` → `audit`, `crypto` / `fwCrypto` → `bCrypto`, `dbMod` / `dbModule` → `db`, etc.) — every minority site renamed per the same canonical-name map. (3) **dbStore seal round-trip test** — the v0.9.15 test suite covered seal-falls-back-when-vault-not-ready and cross-process-sealed-row-preserved, but did NOT exercise the actual default-ON seal/unseal path because the test environment didn't `b.vault.init(...)`. New `testDbStoreSealRoundTripWithVault` bootstraps a plaintext vault, builds a dbStore with `seal: true`, writes a record + reads it back, and asserts (a) `headers` + `body` columns carry the `vault:` envelope on disk, (b) the round-trip restores the original values, and (c) `status_code` stays plaintext so forensic SELECTs still work without unsealing.
12
+ - v0.9.15 (2026-05-13) — **`b.middleware.idempotencyKey.dbStore` hardening + framework-wide `require()` binding-name consistency.** Two operator-surfaced gaps closed: (1) **dbStore now hashes keys + seals body/headers by default.** Operator-supplied idempotency keys sometimes carry PII (order numbers, emails, vendor prefixes); the `k` column previously stored them raw, leaving every DB dump as a PII surface. v0.9.15 sha3-512 namespace-hashes the key via `b.crypto.namespaceHash("idempotency-key", key)` before insert/lookup — round-trips are transparent (operators still pass raw keys), but the DB never sees the original. The schema also splits the previous single-`v` JSON-envelope column into discrete `fingerprint` / `status_code` / `headers` / `body` / `expires_at` columns; `headers` + `body` are sealed via `b.cryptoField.sealRow` (vault-managed AEAD envelope) when vault is initialized, so a DB dump leaks neither cached response bodies nor headers. Non-sealed columns (`status_code`, `fingerprint`, `expires_at`) stay forensic-queryable. Both defaults are operator-opt-out via `opts.hashKeys: false` and `opts.seal: false`; the seal path silently falls back to plaintext + emits an `idempotency.seal_skipped_no_vault` audit warning on first use when vault isn't ready, so test fixtures and boot scripts still work. **Schema migration**: v0.9.15's split columns are incompatible with v0.9.14's single-`v` column — operators with a v0.9.14 idempotency table `DROP TABLE <tableName>;` (or pick a fresh `tableName`) before upgrading. Pre-v1 framework breaks across patch versions for security correctness. (2) **New `require-binding-name` codebase-patterns detector enforces consistent `var X = require("M")` names framework-wide.** Inconsistent names (`fs` vs `nodeFs`, `crypto` vs `nodeCrypto`, `path` vs `nodePath`, `nb` vs `numericBounds`) made `grep` across the lib unreliable and let reviewers miss shadowing bugs (`var crypto = require("crypto")` collides with the framework's own `b.crypto`). The detector carries a `CANONICAL_REQUIRE_BINDINGS` map with safety-first defaults: Node built-ins get a `node<X>` prefix (`nodeFs` / `nodePath` / `nodeCrypto` / `nodeStream` / `nodeTls` / `nodeUrl`) so a local var named `fs` / `path` / `crypto` can never shadow them; the framework's own `lib/crypto.js` binds as `bCrypto` (matches the `b.crypto` public-namespace shape and doesn't shadow node:crypto). Modules without a declared canonical fall back to majority-wins (most-sites name wins, alphabetical tiebreak). Fix is rename, not allowlist — every minority site was updated. **Sweep**: 184 require-binding renames across 108 framework files in this release; primitives + tests unchanged in surface. (3) **`b.graphqlFederation` internal `_timingSafeEqual` now routes through `b.crypto.timingSafeEqual`** (was re-implementing the length-tolerant wrapper inline; the new require-binding-name detector surfaced this; same-patch fix per the audit-existing-code rule).
11
13
  - v0.9.14 (2026-05-13) — **Audit-existing-code sweep: `safeSql.quoteIdentifier` adopted across every framework primitive that interpolates SQL identifiers; new `raw-sql-identifier-interpolation` detector seals the bug class.** Codex P1 on PR #44 flagged that `dbStore.get`'s expired-row cleanup was an unconditional `DELETE WHERE k = ?` between SELECT and DELETE — in a multi-process deployment another process could upsert the same key in the race window, and the unconditional delete would erase the fresh row. Fix: scope the delete by the observed `expires_at`. While reviewing, a wider gap surfaced — every `db.prepare("CREATE TABLE " + tableName + ...)` site in the framework had been concatenating identifiers raw, sometimes with inline shape-regex validation that varied per module. The framework already shipped `b.safeSql.quoteIdentifier(name, dialect?)` for exactly this; per the audit-existing-code rule the same patch (a) routes every site through the helper (`lib/audit.js` segregation-of-duties trigger DDL, `lib/dsr.js` ticket store, `lib/inbox.js` message-receive table, `lib/middleware/idempotency-key.js` dbStore, `lib/vault/rotate.js` column-rotation DDL) and (b) adds a `raw-sql-identifier-interpolation` codebase-patterns detector so the bug class can't return. The detector skips variables whose names signal already-quoted identifiers (`q<X>` / `Q_<X>` / `quoted<X>` prefix), so future primitives that use the helper read naturally. **Plus: bounded JSON parse for two file-/DB-backed primitives.** `b.metrics.snapshot.read` and `b.middleware.idempotencyKey.dbStore.get` previously used bare `JSON.parse` with `allow:bare-json-parse` markers; both are read by processes separate from where they were written (CLI/sidecar reads daemon-written snapshot; multi-process fleet shares DB) where a hostile or misbehaving writer could plant a multi-GB value and OOM the reader. Both now route through `b.safeJson.parse(raw, { maxBytes: 4 MiB })`. **Three new primitives — `b.crypto.hashFilesParallel`, `b.pqcAgent.reload`, `b.middleware.idempotencyKey.dbStore` — plus republish of v0.9.13's surface**. v0.9.13's npm-publish workflow failed at the wiki-e2e gate (the Codex P1 fix removed the `opts` parameter from `b.selfUpdate.standaloneVerifier.verify` but the `@signature` JSDoc still declared four arguments — three vs. four arity drift). The v0.9.13 git tag + GH release reached operators but the npm tarball did not; the registry stayed at v0.9.12. v0.9.14 carries v0.9.13's entire shipped surface (circuitBreaker.create({...}) opts-object fix + `b.selfUpdate.standaloneVerifier` + `b.metrics.snapshot` + `b.retry.withBreaker`) plus three additional Tier 2 primitives surfaced by the same downstream consumer that flagged the v0.9.13 batch. (1) **`b.crypto.hashFilesParallel(filePaths, opts?)`** — parallel multi-digest hashing for many files in a single read pass per file. Worker-pool concurrency cap (default `min(8, paths.length)`, 1..256), operator-tunable `algorithms` list (default `["sha256", "sha3-512"]`), optional `onProgress(completed, total)` callback (throws swallowed). Returns rows in the same order as input. The common consumer-side reason to reach for this is SBOM regeneration / vendor-data integrity sweeps / release-asset bundling — situations where N files each need both SHA-256 (legacy compat) and SHA-3-512 (PQC-first) digests and rolling a worker pool by hand has cost a downstream consumer the same two-loop, capture-N-promises, settle-Q boilerplate every release. (2) **`b.pqcAgent.reload()`** — tear down the lazily-built default agent and reset to null so the next `b.pqcAgent.agent` access rebuilds against current TLS posture + `b.network.tls.applyToContext` output. Long-running daemons that rotate the framework's TLS posture (TLS-pinset reload, certificate-pinset refresh, `C.TLS_GROUP_PREFERENCE` update behind a feature flag) need a way to re-source the outbound `https.Agent` without forking a new process. `reload()` calls `.destroy()` on the existing default agent (Node closes idle keep-alive sockets, lets in-flight sockets complete) then nulls the cache. Agents handed out via explicit `b.pqcAgent.create()` are unaffected. Returns `{ destroyed: boolean }`. (3) **`b.middleware.idempotencyKey.dbStore({ db, tableName?, init? })`** — persistent-backed store for the `idempotencyKey` middleware. Same three-method interface as `memoryStore` (`get` / `set` / `delete`) but stores records in any sqlite-shaped database (`{ prepare(sql) → { run, get, all } }`) — the framework's internal `b.db`, an operator-supplied better-sqlite3 instance, or a custom adapter. Use this instead of `memoryStore` when (a) multiple processes share the request-handling fleet so retries can land on a different process than the original, (b) the daemon may restart between the original request and the retry (graceful rolling deploy, OOM kill), or (c) audit / compliance review needs to walk historic idempotency-cache decisions queryable via `SELECT * FROM <tableName>`. TTL is lazily enforced at read time; `set()` upserts on conflict so concurrent retries on different processes don't error. The `tableName` is validated via `b.safeSql.validateIdentifier` (ASCII identifier shape, 63-char cap, no reserved words). (4) **Internal fix**: `b.apiSnapshot.read` now passes `maxBytes: 64 MiB` to `safeJson.parse` — the framework-generated snapshot file outgrew safeJson's 1 MiB default after v0.9.13. Operators consuming `@blamejs/core` via npm jump from v0.9.12 directly to v0.9.14; v0.9.13's content is included.
12
14
  - v0.9.13 (2026-05-13) — **Two `b.circuitBreaker.create` / `b.retry` bug fixes plus three new operator-facing primitives: `b.selfUpdate.standaloneVerifier`, `b.metrics.snapshot`, `b.retry.withBreaker`**. (1) `b.circuitBreaker.create({...})` was rejecting the documented opts-object call shape with `name must be a non-empty string, got object` — every consumer following the docstring hit a hard error. The factory now reads `opts.name` (defaulting to empty string) and forwards to the internal `CircuitBreaker(name, opts)` constructor. (2) The breaker's open-circuit error code was documented as `retry/circuit-open` but the runtime threw `CIRCUIT_OPEN`. The docstring is corrected to match the runtime; an alias rename will follow with a deprecation cycle in a future minor. (3) **`b.selfUpdate.standaloneVerifier`** — zero-dep verifier for install-pipeline contexts that run BEFORE the framework is installed (Dockerfile build stages, `install.sh`, `update.sh`, SEA-bundle verification at deploy time). Surface: `verify(assetPath, sigPath, pubkeyPem, opts?)` returns `{ ok, sha3_512, sha256, alg }`. Streams the asset in 64 KiB chunks through SHA-256 + SHA-3-512 + the signature verifier in parallel — multi-GB SEA bundles don't OOM the install runner. Supports ECDSA P-384 (both IEEE-P1363 96-byte and DER encodings), Ed25519, and ML-DSA-87. Detects signature format from length so `verifier.verify(...)` runs exactly once (calling it twice returns stale state and silently passes tampered assets). Module is hermetic: `node:crypto` + `node:fs` only, no framework imports. Operators copy the file via `cp "$(node -p "require('@blamejs/core').selfUpdate.standaloneVerifier.path")" install/standalone-verifier.js` into version control on their side. (4) **`b.metrics.snapshot`** — out-of-process metrics export for long-running daemons. `startWriter({ path, intervalMs, fields })` atomically flushes a JSON snapshot (first flush synchronous so the file exists by return-time; subsequent flushes on the interval with `.unref()`; `stop()` clears + final-flushes). `read(path)` parses with shape validation (writtenAt + fields). `render(snap, { format, prefix })` produces operator-readable text or Prometheus 0.0.4 exposition (gauge metrics, prefixed; only finite numeric scalars with prom-compatible names emit; invalid-name / non-numeric / non-finite fields skipped silently). Lets a CLI process scrape a daemon's live metrics without opening an HTTP port. (5) **`b.retry.withBreaker(fn, { retry, breaker })`** — composition primitive collapsing the two-line wrapper every consumer rolls: `breaker.wrap(() => retry.withRetry(fn, opts.retry))`. One breaker call per retry loop (the retry budget is INSIDE the breaker's accounting, so a single transient burst doesn't open the breaker spuriously). Throws on non-function `fn` or breaker without `.wrap`.
13
15
  - v0.9.12 (2026-05-13) — **Republish of v0.9.10 / v0.9.11 — `npm audit signatures` grep widened for the npm-message variant that fires post-v0.9.11**. The publish workflow's "Verify npm registry signing chain" step treats an empty-tree result as success (the framework's zero-runtime-deps posture means `npm audit signatures --omit dev` finds nothing to audit). The exact phrasing has drifted across npm versions: older npm prints `found no installed dependencies to audit`; newer npm (the version on the GH Actions runner post-v0.9.11) prints `found no dependencies to audit that were installed from a supported registry`. The shell guard's grep only matched the older phrasing, so v0.9.11's publish failed at the audit-signatures gate even though every other step succeeded. The grep is now `no (installed )?dependencies to audit` — covers both known empty-tree variants. v0.9.10's broken-smoke fix (added `npm install` before smoke) plus v0.9.12's audit-signatures-grep fix together complete the publish-pipeline repair. v0.9.12 is functionally identical to v0.9.10's intended surface. Operators stuck at v0.9.9 (because v0.9.10 + v0.9.11 never reached the npm registry) jump directly to v0.9.12.
package/lib/a2a-tasks.js CHANGED
@@ -92,14 +92,14 @@ function _emitAudit(action, metadata, outcome) {
92
92
  } catch (_e) { /* best-effort */ }
93
93
  }
94
94
 
95
- var crypto = lazyRequire(function () { return require("./crypto"); });
95
+ var bCrypto = lazyRequire(function () { return require("./crypto"); });
96
96
 
97
97
  // _newTaskId is reserved for the operator-handler path that mints
98
98
  // peer-assigned task IDs server-side. The underscore prefix already
99
99
  // satisfies the framework's unused-var policy so the helper stays
100
100
  // available without an explicit disable directive.
101
101
  function _newTaskId() {
102
- return crypto().generateToken(12); // allow:raw-byte-literal — 96-bit task id, not byte arithmetic on payload
102
+ return bCrypto().generateToken(12); // allow:raw-byte-literal — 96-bit task id, not byte arithmetic on payload
103
103
  }
104
104
 
105
105
  function _validateTaskShape(task, where) {
package/lib/a2a.js CHANGED
@@ -31,10 +31,10 @@
31
31
  * Linux Foundation A2A (Agent-to-Agent) standard — agents advertise identity, declared capabilities, endpoints, and policies via a signed "agent card" that a peer agent fetches before initiating collaboration.
32
32
  */
33
33
 
34
- var crypto = require("./crypto");
34
+ var bCrypto = require("./crypto");
35
35
  var canonicalJson = require("./canonical-json");
36
36
  var C = require("./constants");
37
- var nb = require("./numeric-bounds");
37
+ var numericBounds = require("./numeric-bounds");
38
38
  var audit = require("./audit");
39
39
  var { A2aError } = require("./framework-error");
40
40
 
@@ -230,7 +230,7 @@ function signCard(card, privateKeyPem, opts) {
230
230
  "a2a.signCard: privateKeyPem required");
231
231
  }
232
232
 
233
- nb.requirePositiveFiniteIntIfPresent(opts.ttlMs, "a2a.signCard: opts.ttlMs", errorClass, "BAD_TTL");
233
+ numericBounds.requirePositiveFiniteIntIfPresent(opts.ttlMs, "a2a.signCard: opts.ttlMs", errorClass, "BAD_TTL");
234
234
  var ttlMs = opts.ttlMs || C.TIME.hours(24);
235
235
  var signedAt = Date.now();
236
236
  var expiresAt = signedAt + ttlMs;
@@ -241,11 +241,11 @@ function signCard(card, privateKeyPem, opts) {
241
241
  expiresAt: expiresAt,
242
242
  };
243
243
  var canonical = canonicalize(envelopePayload);
244
- var digest = crypto.shake256
245
- ? crypto.shake256(Buffer.from(canonical, "utf8"), SHAKE256_BYTES)
244
+ var digest = bCrypto.shake256
245
+ ? bCrypto.shake256(Buffer.from(canonical, "utf8"), SHAKE256_BYTES)
246
246
  : null;
247
247
  var dataToSign = digest ? digest : Buffer.from(canonical, "utf8");
248
- var signature = crypto.sign(dataToSign, privateKeyPem);
248
+ var signature = bCrypto.sign(dataToSign, privateKeyPem);
249
249
 
250
250
  if (auditOn) {
251
251
  audit.safeEmit({
@@ -300,8 +300,8 @@ function signCard(card, privateKeyPem, opts) {
300
300
  function verifyCard(envelope, publicKeyPem, opts) {
301
301
  opts = opts || {};
302
302
  var errorClass = opts.errorClass || A2aError;
303
- nb.requirePositiveFiniteIntIfPresent(opts.maxBytes, "a2a.verifyCard: opts.maxBytes", errorClass, "BAD_MAX_BYTES");
304
- nb.requireNonNegativeFiniteIntIfPresent(opts.clockSkewMs, "a2a.verifyCard: opts.clockSkewMs", errorClass, "BAD_SKEW");
303
+ numericBounds.requirePositiveFiniteIntIfPresent(opts.maxBytes, "a2a.verifyCard: opts.maxBytes", errorClass, "BAD_MAX_BYTES");
304
+ numericBounds.requireNonNegativeFiniteIntIfPresent(opts.clockSkewMs, "a2a.verifyCard: opts.clockSkewMs", errorClass, "BAD_SKEW");
305
305
  var maxBytes = opts.maxBytes || C.BYTES.kib(64);
306
306
  var clockSkewMs = opts.clockSkewMs !== undefined ? opts.clockSkewMs : C.TIME.minutes(5);
307
307
  var expectedIssuer = typeof opts.expectedIssuer === "string" ? opts.expectedIssuer : null;
@@ -354,8 +354,8 @@ function verifyCard(envelope, publicKeyPem, opts) {
354
354
  if (Buffer.byteLength(canonical, "utf8") > maxBytes) {
355
355
  return { valid: false, claims: null, reason: "card-too-large" };
356
356
  }
357
- var digest = crypto.shake256
358
- ? crypto.shake256(Buffer.from(canonical, "utf8"), SHAKE256_BYTES)
357
+ var digest = bCrypto.shake256
358
+ ? bCrypto.shake256(Buffer.from(canonical, "utf8"), SHAKE256_BYTES)
359
359
  : null;
360
360
  var dataToVerify = digest ? digest : Buffer.from(canonical, "utf8");
361
361
  var sigBuf;
@@ -363,7 +363,7 @@ function verifyCard(envelope, publicKeyPem, opts) {
363
363
  catch (_e) {
364
364
  return { valid: false, claims: null, reason: "signature-base64-bad" };
365
365
  }
366
- var ok = crypto.verify(dataToVerify, sigBuf, publicKeyPem);
366
+ var ok = bCrypto.verify(dataToVerify, sigBuf, publicKeyPem);
367
367
  if (!ok) {
368
368
  if (auditOn) {
369
369
  audit.safeEmit({
package/lib/acme.js CHANGED
@@ -940,8 +940,8 @@ function create(opts) {
940
940
  throw _err("acme/bad-token", "tlsAlpn01KeyAuthorization: token must be a non-empty string", true);
941
941
  }
942
942
  var keyAuth = token + "." + _jwkThumbprint(publicJwk);
943
- var crypto = require("node:crypto");
944
- return crypto.createHash("sha256").update(keyAuth, "utf8").digest();
943
+ var nodeCrypto = require("node:crypto");
944
+ return nodeCrypto.createHash("sha256").update(keyAuth, "utf8").digest();
945
945
  }
946
946
 
947
947
  /**
@@ -1041,14 +1041,14 @@ function create(opts) {
1041
1041
  throw _err("acme/bad-ttl",
1042
1042
  "dnsAccount01ChallengeRecord: ttl must be a positive integer <= 86400 seconds", true);
1043
1043
  }
1044
- var crypto = require("node:crypto");
1044
+ var nodeCrypto = require("node:crypto");
1045
1045
  // Account label: lowercase base32 of first 10 bytes of SHA-256(accountUrl)
1046
1046
  // (per draft-ietf-acme-dns-account-label §3.1 — 80-bit truncated label).
1047
- var hash = crypto.createHash("sha256").update(state.accountUrl, "utf8").digest();
1047
+ var hash = nodeCrypto.createHash("sha256").update(state.accountUrl, "utf8").digest();
1048
1048
  var label = _base32lc(hash.subarray(0, 10));
1049
1049
  // Record value: same key-authorization digest shape as dns-01.
1050
1050
  var keyAuth = token + "." + _jwkThumbprint(publicJwk);
1051
- var digest = crypto.createHash("sha256").update(keyAuth, "utf8").digest();
1051
+ var digest = nodeCrypto.createHash("sha256").update(keyAuth, "utf8").digest();
1052
1052
  return {
1053
1053
  name: "_" + label + "._acme-challenge." + opts2.identifier,
1054
1054
  value: _b64u(digest),
package/lib/ai-input.js CHANGED
@@ -13,7 +13,7 @@
13
13
  */
14
14
 
15
15
  var C = require("./constants");
16
- var nb = require("./numeric-bounds");
16
+ var numericBounds = require("./numeric-bounds");
17
17
  var audit = require("./audit");
18
18
  var { AiInputError } = require("./framework-error");
19
19
 
@@ -70,7 +70,7 @@ function _featuresOf(input) {
70
70
  function classify(input, opts) {
71
71
  opts = opts || {};
72
72
  var errorClass = opts.errorClass || AiInputError;
73
- nb.requirePositiveFiniteIntIfPresent(opts.maxBytes, "aiInput.classify: opts.maxBytes", errorClass, "BAD_MAX_BYTES");
73
+ numericBounds.requirePositiveFiniteIntIfPresent(opts.maxBytes, "aiInput.classify: opts.maxBytes", errorClass, "BAD_MAX_BYTES");
74
74
  var maxBytes = opts.maxBytes || C.BYTES.kib(64);
75
75
  var auditOn = opts.audit !== false;
76
76
 
package/lib/api-key.js CHANGED
@@ -34,7 +34,7 @@
34
34
  * Long-lived API token primitives — generate / verify / revoke / rotate; sealed at rest; per-key scope + rate-limit.
35
35
  */
36
36
 
37
- var crypto = require("./crypto");
37
+ var bCrypto = require("./crypto");
38
38
  var credentialHash = require("./credential-hash");
39
39
  var safeJson = require("./safe-json");
40
40
  var lazyRequire = require("./lazy-require");
@@ -345,8 +345,8 @@ function create(opts) {
345
345
  async function issue(issueOpts) {
346
346
  cluster.requireLeader();
347
347
  _validateIssueOpts(issueOpts);
348
- var idHex = crypto.generateToken(idBytes);
349
- var secretHex = crypto.generateToken(secretBytes);
348
+ var idHex = bCrypto.generateToken(idBytes);
349
+ var secretHex = bCrypto.generateToken(secretBytes);
350
350
  var compositeId = _composedId(namespace, idHex);
351
351
  var nowMs = clock();
352
352
  var scopes = issueOpts.scopes || [];
@@ -552,7 +552,7 @@ function create(opts) {
552
552
  if (existing.revokedAt != null) {
553
553
  throw _err("REVOKED", "apiKey.rotate: id '" + idHex + "' is revoked");
554
554
  }
555
- var newSecretHex = crypto.generateToken(secretBytes);
555
+ var newSecretHex = bCrypto.generateToken(secretBytes);
556
556
  var newHash = await credentialHash.hash(newSecretHex, { algo: hashAlgo });
557
557
  var nowMs = clock();
558
558
 
@@ -50,8 +50,8 @@
50
50
  * Public-API surface walker plus breaking-change detector — the framework's LTS-contract enforcement at the type level.
51
51
  */
52
52
 
53
- var fs = require("fs");
54
- var nb = require("./numeric-bounds");
53
+ var nodeFs = require("fs");
54
+ var numericBounds = require("./numeric-bounds");
55
55
  var safeJson = require("./safe-json");
56
56
  var { FrameworkError } = require("./framework-error");
57
57
 
@@ -147,7 +147,7 @@ function capture(target, opts) {
147
147
  throw new ApiSnapshotError("api-snapshot/bad-target",
148
148
  "capture: target must be a module's exports object");
149
149
  }
150
- var maxDepth = nb.isPositiveFiniteInt(opts.maxDepth) ? opts.maxDepth : DEFAULT_MAX_DEPTH;
150
+ var maxDepth = numericBounds.isPositiveFiniteInt(opts.maxDepth) ? opts.maxDepth : DEFAULT_MAX_DEPTH;
151
151
  var skipUnderscore = opts.skipUnderscore !== false;
152
152
  var snapshot = _walkNode(target, 0, maxDepth, new Set(), skipUnderscore);
153
153
  if (snapshot.type !== "object") {
@@ -199,7 +199,7 @@ function write(snapshot, filePath) {
199
199
  createdAt: snapshot.createdAt,
200
200
  exports: snapshot.exports,
201
201
  };
202
- fs.writeFileSync(filePath, JSON.stringify(canonical, null, 2) + "\n", { mode: 0o644 });
202
+ nodeFs.writeFileSync(filePath, JSON.stringify(canonical, null, 2) + "\n", { mode: 0o644 });
203
203
  return filePath;
204
204
  }
205
205
 
@@ -230,12 +230,12 @@ function read(filePath) {
230
230
  throw new ApiSnapshotError("api-snapshot/bad-path",
231
231
  "read: filePath is required");
232
232
  }
233
- if (!fs.existsSync(filePath)) {
233
+ if (!nodeFs.existsSync(filePath)) {
234
234
  throw new ApiSnapshotError("api-snapshot/missing",
235
235
  "read: snapshot file not found at " + filePath);
236
236
  }
237
237
  var raw;
238
- try { raw = fs.readFileSync(filePath, "utf8"); }
238
+ try { raw = nodeFs.readFileSync(filePath, "utf8"); }
239
239
  catch (e) {
240
240
  throw new ApiSnapshotError("api-snapshot/read-failed",
241
241
  "read: cannot read " + filePath + ": " + ((e && e.message) || String(e)));
@@ -42,7 +42,7 @@
42
42
  */
43
43
 
44
44
  var safeAsync = require("./safe-async");
45
- var nb = require("./numeric-bounds");
45
+ var numericBounds = require("./numeric-bounds");
46
46
  var tracing = null;
47
47
  try { tracing = require("./tracing"); } catch (_e) { /* tracing optional */ }
48
48
  var { defineClass } = require("./framework-error");
@@ -91,7 +91,7 @@ var DEFAULT_GRACE_MS = C.TIME.seconds(30);
91
91
  */
92
92
  function create(opts) {
93
93
  opts = opts || {};
94
- nb.requirePositiveFiniteIntIfPresent(opts.graceMs,
94
+ numericBounds.requirePositiveFiniteIntIfPresent(opts.graceMs,
95
95
  "app-shutdown.create: opts.graceMs", AppShutdownError, "app-shutdown/bad-grace-ms");
96
96
  var graceMs = opts.graceMs !== undefined ? opts.graceMs : DEFAULT_GRACE_MS;
97
97
  var phases = Array.isArray(opts.phases) ? opts.phases.slice() : [];
package/lib/app.js CHANGED
@@ -89,8 +89,8 @@
89
89
  * level tables still get the framework tables (sessions, queue jobs,
90
90
  * audit_log, consent_log).
91
91
  */
92
- var fs = require("fs");
93
- var path = require("path");
92
+ var nodeFs = require("fs");
93
+ var nodePath = require("path");
94
94
  var appShutdown = require("./app-shutdown");
95
95
  var C = require("./constants");
96
96
  var cluster = require("./cluster");
@@ -123,9 +123,9 @@ async function createApp(opts) {
123
123
  if (!opts.dataDir || typeof opts.dataDir !== "string") {
124
124
  throw new Error("createApp: opts.dataDir is required");
125
125
  }
126
- var dataDir = path.resolve(opts.dataDir);
127
- if (!fs.existsSync(dataDir)) {
128
- fs.mkdirSync(dataDir, { recursive: true });
126
+ var dataDir = nodePath.resolve(opts.dataDir);
127
+ if (!nodeFs.existsSync(dataDir)) {
128
+ nodeFs.mkdirSync(dataDir, { recursive: true });
129
129
  }
130
130
 
131
131
  // ---- 1. Vault ----
package/lib/archive.js CHANGED
@@ -48,9 +48,9 @@
48
48
  * ZIP archive creation primitive.
49
49
  */
50
50
  var zlib = require("node:zlib");
51
- var fs = require("node:fs");
51
+ var nodeFs = require("node:fs");
52
52
  var nodeCrypto = require("node:crypto");
53
- var stream = require("node:stream");
53
+ var nodeStream = require("node:stream");
54
54
  var streamPromises = require("node:stream/promises");
55
55
  var C = require("./constants");
56
56
  var { defineClass } = require("./framework-error");
@@ -159,7 +159,7 @@ function zip() {
159
159
  // Duck-type: Readable instance or any object exposing .pipe + .on +
160
160
  // a `readable` flag / readableState. Avoids importing every consumer's
161
161
  // stream class; matches Node's own stream-detection pattern.
162
- return !!o && (o instanceof stream.Readable ||
162
+ return !!o && (o instanceof nodeStream.Readable ||
163
163
  (typeof o.pipe === "function" && typeof o.on === "function"));
164
164
  }
165
165
 
@@ -323,7 +323,7 @@ function zip() {
323
323
 
324
324
  function writeTo(filepath) {
325
325
  var buf = toBuffer();
326
- fs.writeFileSync(filepath, buf);
326
+ nodeFs.writeFileSync(filepath, buf);
327
327
  return buf.length;
328
328
  }
329
329
 
@@ -379,7 +379,7 @@ function zip() {
379
379
  // CRC tap — a passthrough Transform that observes uncompressed bytes
380
380
  // and updates usize / CRC before forwarding to the next stage. Avoids
381
381
  // consuming the source twice via parallel listeners.
382
- var crcTap = new stream.Transform({
382
+ var crcTap = new nodeStream.Transform({
383
383
  transform: function (chunk, enc, cb) {
384
384
  usize += chunk.length;
385
385
  _crcChunk(chunk);
@@ -395,7 +395,7 @@ function zip() {
395
395
  // may leak to dest on failure, but no EOCD is ever written, so
396
396
  // consumers see a broken stream rather than a half-archive that
397
397
  // pretends to be complete.
398
- var sinkWritable = new stream.Writable({
398
+ var sinkWritable = new nodeStream.Writable({
399
399
  write: function (chunk, enc, cb) {
400
400
  csize += chunk.length;
401
401
  var ok = writable.write(chunk);
@@ -411,7 +411,7 @@ function zip() {
411
411
  }
412
412
  } else {
413
413
  // STORE: pipe source -> crcTap -> writable. csize === usize.
414
- var storeCollect = new stream.Writable({
414
+ var storeCollect = new nodeStream.Writable({
415
415
  write: function (chunk, enc, cb) {
416
416
  csize += chunk.length;
417
417
  var ok = writable.write(chunk);
@@ -445,7 +445,7 @@ function zip() {
445
445
  var returnReadable = !writable;
446
446
  var dest = writable;
447
447
  if (returnReadable) {
448
- dest = new stream.PassThrough();
448
+ dest = new nodeStream.PassThrough();
449
449
  } else if (typeof writable.write !== "function") {
450
450
  throw new ArchiveError("archive/bad-writable",
451
451
  "toStream: writable must be a Writable (or omit to receive a Readable)");
@@ -21,7 +21,7 @@
21
21
  */
22
22
 
23
23
  var nodeCrypto = require("crypto");
24
- var blamejsCrypto = require("./crypto");
24
+ var bCrypto = require("./crypto");
25
25
  var C = require("./constants");
26
26
 
27
27
  var ARGON2ID = "argon2id";
@@ -137,7 +137,7 @@ async function verify(stored, plain) {
137
137
  var actual;
138
138
  try { actual = await _runArgon2(message, dec.salt, dec.params, dec.hash.length); }
139
139
  catch (_e) { return false; }
140
- return blamejsCrypto.timingSafeEqual(actual, dec.hash);
140
+ return bCrypto.timingSafeEqual(actual, dec.hash);
141
141
  }
142
142
 
143
143
  function needsRehash(stored, opts) {