@blamejs/core 0.9.14 → 0.9.15

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 (112) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/lib/a2a.js +11 -11
  3. package/lib/acme.js +5 -5
  4. package/lib/ai-input.js +2 -2
  5. package/lib/api-key.js +4 -4
  6. package/lib/api-snapshot.js +6 -6
  7. package/lib/app-shutdown.js +2 -2
  8. package/lib/app.js +5 -5
  9. package/lib/archive.js +8 -8
  10. package/lib/argon2-builtin.js +2 -2
  11. package/lib/atomic-file.js +53 -53
  12. package/lib/audit-sign.js +8 -8
  13. package/lib/audit-tools.js +22 -22
  14. package/lib/auth/dpop.js +3 -3
  15. package/lib/auth/sd-jwt-vc.js +2 -2
  16. package/lib/backup/bundle.js +17 -17
  17. package/lib/backup/index.js +36 -36
  18. package/lib/budr.js +3 -3
  19. package/lib/bundler.js +20 -20
  20. package/lib/circuit-breaker.js +4 -4
  21. package/lib/cli.js +25 -26
  22. package/lib/cluster.js +2 -2
  23. package/lib/compliance-sanctions.js +2 -2
  24. package/lib/config-drift.js +15 -15
  25. package/lib/content-credentials.js +4 -4
  26. package/lib/credential-hash.js +3 -3
  27. package/lib/daemon.js +19 -19
  28. package/lib/db-file-lifecycle.js +24 -24
  29. package/lib/db-schema.js +2 -2
  30. package/lib/db.js +35 -35
  31. package/lib/dev.js +10 -10
  32. package/lib/dr-runbook.js +5 -5
  33. package/lib/dual-control.js +2 -2
  34. package/lib/external-db-migrate.js +2 -2
  35. package/lib/external-db.js +2 -2
  36. package/lib/fdx.js +2 -2
  37. package/lib/file-upload.js +30 -30
  38. package/lib/flag-providers.js +4 -4
  39. package/lib/gate-contract.js +5 -5
  40. package/lib/graphql-federation.js +4 -7
  41. package/lib/honeytoken.js +6 -6
  42. package/lib/http-client-cookie-jar.js +6 -6
  43. package/lib/http-client.js +18 -18
  44. package/lib/i18n.js +5 -5
  45. package/lib/keychain.js +9 -9
  46. package/lib/legal-hold.js +2 -2
  47. package/lib/local-db-thin.js +9 -9
  48. package/lib/log-stream-local.js +17 -17
  49. package/lib/log-stream-syslog.js +2 -2
  50. package/lib/log-stream.js +3 -3
  51. package/lib/mail-bounce.js +2 -2
  52. package/lib/mail-mdn.js +2 -2
  53. package/lib/mail-srs.js +2 -2
  54. package/lib/mail.js +4 -4
  55. package/lib/mcp.js +2 -2
  56. package/lib/metrics.js +2 -2
  57. package/lib/middleware/api-encrypt.js +16 -16
  58. package/lib/middleware/body-parser.js +16 -16
  59. package/lib/middleware/compression.js +3 -3
  60. package/lib/middleware/csp-nonce.js +4 -4
  61. package/lib/middleware/health.js +7 -7
  62. package/lib/middleware/idempotency-key.js +163 -63
  63. package/lib/migrations.js +3 -3
  64. package/lib/mtls-ca.js +26 -26
  65. package/lib/mtls-engine-default.js +5 -5
  66. package/lib/network-dns.js +2 -2
  67. package/lib/network-nts.js +2 -2
  68. package/lib/network-proxy.js +3 -3
  69. package/lib/network-smtp-policy.js +2 -2
  70. package/lib/network-tls.js +17 -17
  71. package/lib/network.js +13 -13
  72. package/lib/notify.js +3 -3
  73. package/lib/object-store/gcs-bucket-ops.js +2 -2
  74. package/lib/object-store/gcs.js +5 -5
  75. package/lib/object-store/index.js +6 -6
  76. package/lib/object-store/local.js +19 -19
  77. package/lib/object-store/sigv4.js +3 -3
  78. package/lib/observability-tracer.js +4 -4
  79. package/lib/otel-export.js +3 -3
  80. package/lib/pagination.js +5 -5
  81. package/lib/parsers/safe-xml.js +3 -3
  82. package/lib/pqc-gate.js +5 -5
  83. package/lib/pubsub-redis.js +2 -2
  84. package/lib/queue-local.js +3 -3
  85. package/lib/queue.js +2 -2
  86. package/lib/redis-client.js +4 -4
  87. package/lib/restore-bundle.js +18 -18
  88. package/lib/restore-rollback.js +34 -34
  89. package/lib/restore.js +16 -16
  90. package/lib/router.js +13 -13
  91. package/lib/sandbox.js +8 -8
  92. package/lib/sec-cyber.js +3 -3
  93. package/lib/security-assert.js +2 -2
  94. package/lib/seeders.js +4 -4
  95. package/lib/self-update.js +18 -18
  96. package/lib/session-device-binding.js +2 -2
  97. package/lib/static.js +22 -22
  98. package/lib/template.js +19 -19
  99. package/lib/testing.js +7 -7
  100. package/lib/tls-exporter.js +5 -5
  101. package/lib/tracing.js +3 -3
  102. package/lib/vault/index.js +11 -11
  103. package/lib/vault/passphrase-ops.js +37 -37
  104. package/lib/vault/passphrase-source.js +2 -2
  105. package/lib/vault/rotate.js +64 -64
  106. package/lib/vault/seal-pem-file.js +26 -26
  107. package/lib/watcher.js +23 -23
  108. package/lib/webhook.js +10 -10
  109. package/lib/worker-pool.js +6 -6
  110. package/lib/ws-client.js +4 -4
  111. package/package.json +1 -1
  112. package/sbom.cdx.json +6 -6
package/lib/template.js CHANGED
@@ -89,8 +89,8 @@
89
89
  * is the second line: even if a template loaded, it can't execute
90
90
  * arbitrary JS — only the limited expression grammar above.
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 lazyRequire = require("./lazy-require");
95
95
  var validateOpts = require("./validate-opts");
96
96
 
@@ -149,13 +149,13 @@ function _resolveViewPath(viewsDir, viewName) {
149
149
  if (viewName.indexOf("..") !== -1 || viewName.indexOf("\0") !== -1) {
150
150
  throw new Error("template: view name contains forbidden character: " + JSON.stringify(viewName));
151
151
  }
152
- var resolved = path.resolve(viewsDir, viewName + ".html");
153
- var resolvedDir = path.resolve(viewsDir);
152
+ var resolved = nodePath.resolve(viewsDir, viewName + ".html");
153
+ var resolvedDir = nodePath.resolve(viewsDir);
154
154
  if (resolved !== resolvedDir &&
155
- !resolved.startsWith(resolvedDir + path.sep)) {
155
+ !resolved.startsWith(resolvedDir + nodePath.sep)) {
156
156
  throw new Error("template: view path escapes viewsDir: " + viewName);
157
157
  }
158
- if (!fs.existsSync(resolved)) {
158
+ if (!nodeFs.existsSync(resolved)) {
159
159
  throw new Error("template: view not found: " + viewName);
160
160
  }
161
161
  return resolved;
@@ -164,11 +164,11 @@ function _resolveViewPath(viewsDir, viewName) {
164
164
  function _resolvePartialPath(viewsDir, partialName) {
165
165
  if (typeof partialName !== "string" || partialName.length === 0) return null;
166
166
  if (partialName.indexOf("..") !== -1 || partialName.indexOf("\0") !== -1) return null;
167
- var resolved = path.resolve(viewsDir, "partials", partialName + ".html");
168
- var partialsDir = path.resolve(viewsDir, "partials");
167
+ var resolved = nodePath.resolve(viewsDir, "partials", partialName + ".html");
168
+ var partialsDir = nodePath.resolve(viewsDir, "partials");
169
169
  if (resolved !== partialsDir &&
170
- !resolved.startsWith(partialsDir + path.sep)) return null;
171
- return fs.existsSync(resolved) ? resolved : null;
170
+ !resolved.startsWith(partialsDir + nodePath.sep)) return null;
171
+ return nodeFs.existsSync(resolved) ? resolved : null;
172
172
  }
173
173
 
174
174
  // ============================================================
@@ -227,7 +227,7 @@ function _resolveExtends(viewsDir, source) {
227
227
  }
228
228
  }
229
229
  var parentPath = _resolveViewPath(viewsDir, parentName);
230
- current = fs.readFileSync(parentPath, "utf8");
230
+ current = nodeFs.readFileSync(parentPath, "utf8");
231
231
  depth++;
232
232
  }
233
233
  return _substituteBlocks(current, allOverrides);
@@ -245,7 +245,7 @@ function _inlinePartials(viewsDir, source, depth) {
245
245
  return source.replace(/\{\{>\s*([A-Za-z_][A-Za-z0-9_-]*)\s*\}\}/g, function (_, name) {
246
246
  var p = _resolvePartialPath(viewsDir, name);
247
247
  if (!p) return ""; // missing partial → silent empty so a stale `{{> name}}` reference doesn't crash the render
248
- return _inlinePartials(viewsDir, fs.readFileSync(p, "utf8"), depth + 1);
248
+ return _inlinePartials(viewsDir, nodeFs.readFileSync(p, "utf8"), depth + 1);
249
249
  });
250
250
  }
251
251
 
@@ -771,10 +771,10 @@ function create(opts) {
771
771
  if (!opts.viewsDir) {
772
772
  throw new Error("template.create({ viewsDir }) is required");
773
773
  }
774
- if (!fs.existsSync(opts.viewsDir)) {
774
+ if (!nodeFs.existsSync(opts.viewsDir)) {
775
775
  throw new Error("template: viewsDir does not exist: " + opts.viewsDir);
776
776
  }
777
- var viewsDir = path.resolve(opts.viewsDir);
777
+ var viewsDir = nodePath.resolve(opts.viewsDir);
778
778
  var cacheOn = opts.cache !== false;
779
779
  var customEscape = typeof opts.escapeHtml === "function" ? opts.escapeHtml : escapeHtml;
780
780
  var astCache = {};
@@ -823,7 +823,7 @@ function create(opts) {
823
823
  function compile(viewName) {
824
824
  if (cacheOn && astCache[viewName]) return astCache[viewName];
825
825
  var viewPath = _resolveViewPath(viewsDir, viewName);
826
- var source = fs.readFileSync(viewPath, "utf8");
826
+ var source = nodeFs.readFileSync(viewPath, "utf8");
827
827
  source = _resolveExtends(viewsDir, source);
828
828
  source = _inlinePartials(viewsDir, source, 0);
829
829
  var tokens = _tokenize(source);
@@ -847,12 +847,12 @@ function create(opts) {
847
847
  function precompileAll() {
848
848
  var compiled = [];
849
849
  function walk(dir, prefix) {
850
- var entries = fs.readdirSync(dir, { withFileTypes: true });
850
+ var entries = nodeFs.readdirSync(dir, { withFileTypes: true });
851
851
  for (var i = 0; i < entries.length; i++) {
852
852
  var e = entries[i];
853
853
  var rel = prefix ? prefix + "/" + e.name : e.name;
854
854
  if (e.isDirectory()) {
855
- walk(path.join(dir, e.name), rel);
855
+ walk(nodePath.join(dir, e.name), rel);
856
856
  } else if (e.isFile() && /\.html$/.test(e.name)) {
857
857
  var viewName = rel.replace(/\.html$/, "");
858
858
  try {
@@ -890,8 +890,8 @@ function create(opts) {
890
890
  var _default = null;
891
891
  function _ensureDefault() {
892
892
  if (!_default) {
893
- var defaultDir = path.resolve(process.cwd(), "views");
894
- if (!fs.existsSync(defaultDir)) {
893
+ var defaultDir = nodePath.resolve(process.cwd(), "views");
894
+ if (!nodeFs.existsSync(defaultDir)) {
895
895
  throw new Error("template.render() default uses <cwd>/views which doesn't exist; " +
896
896
  "call template.create({ viewsDir }) for a custom location");
897
897
  }
package/lib/testing.js CHANGED
@@ -42,7 +42,7 @@
42
42
  * Operator-facing test helpers.
43
43
  */
44
44
 
45
- var fs = require("node:fs");
45
+ var nodeFs = require("node:fs");
46
46
  // testing.js IS the test injector — bypasses b.httpClient by design so
47
47
  // tests can assert on raw request shape. This is the one production
48
48
  // module where direct http.request is the contract.
@@ -792,9 +792,9 @@ async function waitFor(predicate, opts) {
792
792
  * @example
793
793
  * var dir = b.testing.tempDir("my-fixture");
794
794
  * try {
795
- * var nodeFs = require("node:fs");
796
- * var nodePath2 = require("node:path");
797
- * nodeFs.writeFileSync(nodePath2.join(dir.path, "fixture.json"), '{"ok":1}');
795
+ * var fs = require("node:fs");
796
+ * var path = require("node:path");
797
+ * fs.writeFileSync(path.join(dir.path, "fixture.json"), '{"ok":1}');
798
798
  * dir.path.indexOf("my-fixture-") !== -1; // → true
799
799
  * } finally {
800
800
  * dir.cleanup();
@@ -813,9 +813,9 @@ function tempDir(prefix) {
813
813
  "tempDir: prefix must not contain '..', '/', '\\', or null bytes; got " + JSON.stringify(prefix));
814
814
  }
815
815
  // Path containment check mirroring static.js _resolveSafe — verify
816
- // the resolved tempdir is actually inside os.tmpdir() before fs.mkdir.
816
+ // the resolved tempdir is actually inside os.tmpdir() before nodeFs.mkdir.
817
817
  var root = nodePath.resolve(os.tmpdir());
818
- var dirPath = fs.mkdtempSync(nodePath.join(root, prefix + "-"));
818
+ var dirPath = nodeFs.mkdtempSync(nodePath.join(root, prefix + "-"));
819
819
  var resolved = nodePath.resolve(dirPath);
820
820
  if (resolved !== root && !resolved.startsWith(root + nodePath.sep)) {
821
821
  throw _err("BAD_STATE",
@@ -827,7 +827,7 @@ function tempDir(prefix) {
827
827
  cleanup: function () {
828
828
  if (cleanedUp) return;
829
829
  cleanedUp = true;
830
- try { fs.rmSync(resolved, { recursive: true, force: true }); }
830
+ try { nodeFs.rmSync(resolved, { recursive: true, force: true }); }
831
831
  catch (_e) { /* best-effort on Windows locked files */ }
832
832
  },
833
833
  };
@@ -31,10 +31,10 @@
31
31
  * RFC 5705 / RFC 9266 TLS Exporter for binding application-layer keys and tokens to the live TLS session.
32
32
  */
33
33
 
34
- var crypto = require("./crypto");
34
+ var bCrypto = require("./crypto");
35
35
  var C = require("./constants");
36
36
  var lazyRequire = require("./lazy-require");
37
- var nb = require("./numeric-bounds");
37
+ var numericBounds = require("./numeric-bounds");
38
38
  var { TlsExporterError } = require("./framework-error");
39
39
 
40
40
  var _err = TlsExporterError.factory;
@@ -119,7 +119,7 @@ function fromSocket(socketOrReq, opts) {
119
119
  // length is operator-tunable; validate-when-present via numeric-bounds
120
120
  // so a non-finite / negative / NaN input surfaces with the same error
121
121
  // shape every other framework primitive uses for numeric opts.
122
- nb.requirePositiveFiniteIntIfPresent(opts.length,
122
+ numericBounds.requirePositiveFiniteIntIfPresent(opts.length,
123
123
  "tlsExporter.fromSocket: length", TlsExporterError, "BAD_LENGTH");
124
124
  var length = opts.length !== undefined ? opts.length : EXPORTER_LENGTH;
125
125
  if (length < C.BYTES.bytes(16) || length > C.BYTES.bytes(255)) {
@@ -193,7 +193,7 @@ function bindToken(socketOrReq, token) {
193
193
  // does NOT produce the same hash if used in another framework
194
194
  // primitive (e.g., the audit-chain row hash).
195
195
  var labelBuf = Buffer.from("blamejs/tls-exporter/bind/v1", "utf8");
196
- return crypto.sha3Hash(Buffer.concat([labelBuf, exporter, tokenBuf]));
196
+ return bCrypto.sha3Hash(Buffer.concat([labelBuf, exporter, tokenBuf]));
197
197
  }
198
198
 
199
199
  /**
@@ -226,7 +226,7 @@ function verifyTokenBinding(socketOrReq, token, claimedBinding) {
226
226
  if (typeof claimedBinding !== "string" || claimedBinding.length === 0) {
227
227
  return false;
228
228
  }
229
- return crypto.timingSafeEqual(actual, claimedBinding);
229
+ return bCrypto.timingSafeEqual(actual, claimedBinding);
230
230
  }
231
231
 
232
232
  module.exports = {
package/lib/tracing.js CHANGED
@@ -39,7 +39,7 @@
39
39
  */
40
40
 
41
41
  var C = require("./constants");
42
- var crypto = require("./crypto");
42
+ var bCrypto = require("./crypto");
43
43
  var validateOpts = require("./validate-opts");
44
44
  var { defineClass } = require("./framework-error");
45
45
  var { resolveRoute, captureResponseStatus } = require("./request-helpers");
@@ -101,10 +101,10 @@ function _formatTraceparent(traceId, spanId, flags) {
101
101
  }
102
102
 
103
103
  function _newTraceId() {
104
- return crypto.generateToken(W3C_TRACE_ID_BYTES);
104
+ return bCrypto.generateToken(W3C_TRACE_ID_BYTES);
105
105
  }
106
106
  function _newSpanId() {
107
- return crypto.generateToken(W3C_SPAN_ID_BYTES);
107
+ return bCrypto.generateToken(W3C_SPAN_ID_BYTES);
108
108
  }
109
109
 
110
110
  // ---- Pass-through span (used when OTel isn't installed) ----
@@ -62,8 +62,8 @@
62
62
  * @card
63
63
  * Sealed keystore that anchors every other framework subsystem holding secrets at rest: db field encryption, encrypted session storage, audit-log signing keys, OAuth refresh tokens, anything that flows through `b.vault.seal` / `b.vault.unseal`.
64
64
  */
65
- var fs = require("fs");
66
- var path = require("path");
65
+ var nodeFs = require("fs");
66
+ var nodePath = require("path");
67
67
  var atomicFile = require("../atomic-file");
68
68
  var C = require("../constants");
69
69
  var { generateEncryptionKeyPair, encrypt, decrypt } = require("../crypto");
@@ -99,9 +99,9 @@ var log = boot("vault");
99
99
  function resolvePaths(dataDir) {
100
100
  return {
101
101
  dataDir: dataDir,
102
- plaintext: path.join(dataDir, "vault.key"),
103
- sealed: path.join(dataDir, "vault.key.sealed"),
104
- derivedHashSalt: path.join(dataDir, "vault.derived-hash-salt"),
102
+ plaintext: nodePath.join(dataDir, "vault.key"),
103
+ sealed: nodePath.join(dataDir, "vault.key.sealed"),
104
+ derivedHashSalt: nodePath.join(dataDir, "vault.derived-hash-salt"),
105
105
  };
106
106
  }
107
107
 
@@ -118,7 +118,7 @@ function _readOrCreateDerivedHashSalt() {
118
118
  throw new VaultError("vault/not-initialized",
119
119
  "vault.derivedHashSalt() requires init()");
120
120
  }
121
- if (fs.existsSync(paths.derivedHashSalt)) {
121
+ if (nodeFs.existsSync(paths.derivedHashSalt)) {
122
122
  var raw = atomicFile.readSync(paths.derivedHashSalt);
123
123
  if (raw.length !== 32) { // allow:raw-byte-literal — 32-byte (256-bit) salt
124
124
  throw new VaultError("vault/derived-hash-salt-corrupted",
@@ -242,16 +242,16 @@ async function init(opts) {
242
242
  currentMode = mode;
243
243
  paths = resolvePaths(opts.dataDir);
244
244
 
245
- if (!fs.existsSync(paths.dataDir)) {
246
- fs.mkdirSync(paths.dataDir, { recursive: true });
245
+ if (!nodeFs.existsSync(paths.dataDir)) {
246
+ nodeFs.mkdirSync(paths.dataDir, { recursive: true });
247
247
  }
248
248
 
249
249
  // Sweep tmp files left behind by a previously-crashed write
250
250
  atomicFile.cleanOrphans(paths.sealed);
251
251
  atomicFile.cleanOrphans(paths.plaintext);
252
252
 
253
- var hasPlaintext = fs.existsSync(paths.plaintext);
254
- var hasSealed = fs.existsSync(paths.sealed);
253
+ var hasPlaintext = nodeFs.existsSync(paths.plaintext);
254
+ var hasSealed = nodeFs.existsSync(paths.sealed);
255
255
 
256
256
  // Refuse to guess when both files coexist
257
257
  if (hasPlaintext && hasSealed) {
@@ -287,7 +287,7 @@ async function init(opts) {
287
287
  }
288
288
 
289
289
  function initPlaintext() {
290
- if (fs.existsSync(paths.plaintext)) {
290
+ if (nodeFs.existsSync(paths.plaintext)) {
291
291
  var loaded;
292
292
  try {
293
293
  loaded = safeJson.parse(atomicFile.readSync(paths.plaintext), {
@@ -35,8 +35,8 @@
35
35
  * with the original file untouched.
36
36
  */
37
37
 
38
- var fs = require("fs");
39
- var path = require("path");
38
+ var nodeFs = require("fs");
39
+ var nodePath = require("path");
40
40
  var atomicFile = require("../atomic-file");
41
41
  var vaultWrap = require("./wrap");
42
42
  var { defineClass } = require("../framework-error");
@@ -48,10 +48,10 @@ var SEALED_NAME = "vault.key.sealed";
48
48
 
49
49
  function _paths(dataDir) {
50
50
  return {
51
- plaintext: path.join(dataDir, PLAINTEXT_NAME),
52
- plaintextTmp: path.join(dataDir, PLAINTEXT_NAME + ".tmp"),
53
- sealed: path.join(dataDir, SEALED_NAME),
54
- sealedTmp: path.join(dataDir, SEALED_NAME + ".tmp"),
51
+ plaintext: nodePath.join(dataDir, PLAINTEXT_NAME),
52
+ plaintextTmp: nodePath.join(dataDir, PLAINTEXT_NAME + ".tmp"),
53
+ sealed: nodePath.join(dataDir, SEALED_NAME),
54
+ sealedTmp: nodePath.join(dataDir, SEALED_NAME + ".tmp"),
55
55
  };
56
56
  }
57
57
 
@@ -60,7 +60,7 @@ function _requireDataDir(opts) {
60
60
  throw new VaultPassphraseError("vault-passphrase/no-datadir",
61
61
  "opts.dataDir is required (path to the framework data directory)");
62
62
  }
63
- if (!fs.existsSync(opts.dataDir)) {
63
+ if (!nodeFs.existsSync(opts.dataDir)) {
64
64
  throw new VaultPassphraseError("vault-passphrase/no-datadir",
65
65
  "opts.dataDir does not exist: " + opts.dataDir);
66
66
  }
@@ -80,8 +80,8 @@ function _requirePassphrase(opts, fieldName) {
80
80
  // don't have the original write fd around.
81
81
  function _fsyncPath(p) {
82
82
  try {
83
- var fd = fs.openSync(p, "r+");
84
- try { atomicFile.fsync(fd); } finally { fs.closeSync(fd); }
83
+ var fd = nodeFs.openSync(p, "r+");
84
+ try { atomicFile.fsync(fd); } finally { nodeFs.closeSync(fd); }
85
85
  } catch (_e) { /* best-effort across filesystems */ }
86
86
  }
87
87
 
@@ -90,13 +90,13 @@ function _fsyncPath(p) {
90
90
  function preflightSealable(opts) {
91
91
  _requireDataDir(opts);
92
92
  var p = _paths(opts.dataDir);
93
- if (!fs.existsSync(p.plaintext)) {
93
+ if (!nodeFs.existsSync(p.plaintext)) {
94
94
  return { ok: false, reason: "plaintext " + PLAINTEXT_NAME + " does not exist — nothing to seal" };
95
95
  }
96
- if (fs.existsSync(p.sealed)) {
96
+ if (nodeFs.existsSync(p.sealed)) {
97
97
  return { ok: false, reason: SEALED_NAME + " already exists; refusing to overwrite" };
98
98
  }
99
- if (fs.existsSync(p.sealedTmp)) {
99
+ if (nodeFs.existsSync(p.sealedTmp)) {
100
100
  return { ok: false, reason: "stale " + SEALED_NAME + ".tmp from a previous crash; remove it manually after verifying the directory state" };
101
101
  }
102
102
  return { ok: true };
@@ -105,13 +105,13 @@ function preflightSealable(opts) {
105
105
  function preflightUnsealable(opts) {
106
106
  _requireDataDir(opts);
107
107
  var p = _paths(opts.dataDir);
108
- if (!fs.existsSync(p.sealed)) {
108
+ if (!nodeFs.existsSync(p.sealed)) {
109
109
  return { ok: false, reason: SEALED_NAME + " does not exist — nothing to unseal" };
110
110
  }
111
- if (fs.existsSync(p.plaintext)) {
111
+ if (nodeFs.existsSync(p.plaintext)) {
112
112
  return { ok: false, reason: "plaintext " + PLAINTEXT_NAME + " already exists; refusing to overwrite" };
113
113
  }
114
- if (fs.existsSync(p.plaintextTmp)) {
114
+ if (nodeFs.existsSync(p.plaintextTmp)) {
115
115
  return { ok: false, reason: "stale " + PLAINTEXT_NAME + ".tmp from a previous crash; remove it manually after verifying the directory state" };
116
116
  }
117
117
  return { ok: true };
@@ -120,10 +120,10 @@ function preflightUnsealable(opts) {
120
120
  function preflightRotatable(opts) {
121
121
  _requireDataDir(opts);
122
122
  var p = _paths(opts.dataDir);
123
- if (!fs.existsSync(p.sealed)) {
123
+ if (!nodeFs.existsSync(p.sealed)) {
124
124
  return { ok: false, reason: SEALED_NAME + " does not exist — rotate has nothing to operate on" };
125
125
  }
126
- if (fs.existsSync(p.sealedTmp)) {
126
+ if (nodeFs.existsSync(p.sealedTmp)) {
127
127
  return { ok: false, reason: "stale " + SEALED_NAME + ".tmp from a previous crash; remove it manually after verifying the directory state" };
128
128
  }
129
129
  return { ok: true };
@@ -141,39 +141,39 @@ async function seal(opts) {
141
141
  var p = _paths(opts.dataDir);
142
142
  var keepPlaintext = !!opts.keepPlaintext;
143
143
 
144
- var plainBytes = fs.readFileSync(p.plaintext);
144
+ var plainBytes = nodeFs.readFileSync(p.plaintext);
145
145
  var sealedBytes = await vaultWrap.wrap(plainBytes, opts.passphrase);
146
146
 
147
147
  // Step 1: write sealed.tmp + fsync
148
- fs.writeFileSync(p.sealedTmp, sealedBytes, { mode: 0o600 });
148
+ nodeFs.writeFileSync(p.sealedTmp, sealedBytes, { mode: 0o600 });
149
149
  _fsyncPath(p.sealedTmp);
150
150
  atomicFile.fsyncDir(opts.dataDir);
151
151
 
152
152
  // Step 2: round-trip verify the .tmp before committing the rename
153
- var verifyBytes = fs.readFileSync(p.sealedTmp);
153
+ var verifyBytes = nodeFs.readFileSync(p.sealedTmp);
154
154
  var unwrapped;
155
155
  try {
156
156
  unwrapped = await vaultWrap.unwrap(verifyBytes, opts.passphrase);
157
157
  } catch (e) {
158
- try { fs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
158
+ try { nodeFs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
159
159
  throw new VaultPassphraseError("vault-passphrase/verify-failed",
160
160
  "round-trip verification of sealed file failed: " + ((e && e.message) || String(e)) +
161
161
  " — original " + PLAINTEXT_NAME + " is UNCHANGED");
162
162
  }
163
163
  if (Buffer.compare(unwrapped, plainBytes) !== 0) {
164
- try { fs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
164
+ try { nodeFs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
165
165
  throw new VaultPassphraseError("vault-passphrase/verify-mismatch",
166
166
  "round-trip produced different bytes than the original — original " + PLAINTEXT_NAME +
167
167
  " is UNCHANGED. Filesystem may be faulty.");
168
168
  }
169
169
 
170
170
  // Step 3: atomic rename sealed.tmp → sealed
171
- fs.renameSync(p.sealedTmp, p.sealed);
171
+ nodeFs.renameSync(p.sealedTmp, p.sealed);
172
172
  atomicFile.fsyncDir(opts.dataDir);
173
173
 
174
174
  // Step 4: delete plaintext (unless keepPlaintext)
175
175
  if (!keepPlaintext) {
176
- fs.unlinkSync(p.plaintext);
176
+ nodeFs.unlinkSync(p.plaintext);
177
177
  atomicFile.fsyncDir(opts.dataDir);
178
178
  }
179
179
 
@@ -194,7 +194,7 @@ async function unseal(opts) {
194
194
  }
195
195
  var p = _paths(opts.dataDir);
196
196
 
197
- var sealedBytes = fs.readFileSync(p.sealed);
197
+ var sealedBytes = nodeFs.readFileSync(p.sealed);
198
198
  var plainBytes;
199
199
  try {
200
200
  plainBytes = await vaultWrap.unwrap(sealedBytes, opts.passphrase);
@@ -205,25 +205,25 @@ async function unseal(opts) {
205
205
  }
206
206
 
207
207
  // Step 1: write plaintext.tmp + fsync
208
- fs.writeFileSync(p.plaintextTmp, plainBytes, { mode: 0o600 });
208
+ nodeFs.writeFileSync(p.plaintextTmp, plainBytes, { mode: 0o600 });
209
209
  _fsyncPath(p.plaintextTmp);
210
210
  atomicFile.fsyncDir(opts.dataDir);
211
211
 
212
212
  // Step 2: round-trip sanity — re-read tmp and verify
213
- var verifyBytes = fs.readFileSync(p.plaintextTmp);
213
+ var verifyBytes = nodeFs.readFileSync(p.plaintextTmp);
214
214
  if (Buffer.compare(verifyBytes, plainBytes) !== 0) {
215
- try { fs.unlinkSync(p.plaintextTmp); } catch (_e) { /* cleanup */ }
215
+ try { nodeFs.unlinkSync(p.plaintextTmp); } catch (_e) { /* cleanup */ }
216
216
  throw new VaultPassphraseError("vault-passphrase/verify-mismatch",
217
217
  "plaintext.tmp re-read differs from in-memory bytes — filesystem may be faulty. " +
218
218
  SEALED_NAME + " is UNCHANGED");
219
219
  }
220
220
 
221
221
  // Step 3: atomic rename plaintext.tmp → plaintext
222
- fs.renameSync(p.plaintextTmp, p.plaintext);
222
+ nodeFs.renameSync(p.plaintextTmp, p.plaintext);
223
223
  atomicFile.fsyncDir(opts.dataDir);
224
224
 
225
225
  // Step 4: delete sealed file
226
- fs.unlinkSync(p.sealed);
226
+ nodeFs.unlinkSync(p.sealed);
227
227
  atomicFile.fsyncDir(opts.dataDir);
228
228
 
229
229
  return { plaintextPath: p.plaintext };
@@ -245,7 +245,7 @@ async function rotate(opts) {
245
245
  }
246
246
  var p = _paths(opts.dataDir);
247
247
 
248
- var sealedBytes = fs.readFileSync(p.sealed);
248
+ var sealedBytes = nodeFs.readFileSync(p.sealed);
249
249
  var plainBytes;
250
250
  try {
251
251
  plainBytes = await vaultWrap.unwrap(sealedBytes, opts.oldPassphrase);
@@ -257,23 +257,23 @@ async function rotate(opts) {
257
257
  var newSealedBytes = await vaultWrap.wrap(plainBytes, opts.newPassphrase);
258
258
 
259
259
  // Step 1: write new sealed.tmp + fsync
260
- fs.writeFileSync(p.sealedTmp, newSealedBytes, { mode: 0o600 });
260
+ nodeFs.writeFileSync(p.sealedTmp, newSealedBytes, { mode: 0o600 });
261
261
  _fsyncPath(p.sealedTmp);
262
262
  atomicFile.fsyncDir(opts.dataDir);
263
263
 
264
264
  // Step 2: round-trip verify with NEW passphrase, AND assert unwrap
265
265
  // with the OLD passphrase fails — otherwise the rotation didn't take.
266
- var verifyBytes = fs.readFileSync(p.sealedTmp);
266
+ var verifyBytes = nodeFs.readFileSync(p.sealedTmp);
267
267
  var verifyPlain;
268
268
  try { verifyPlain = await vaultWrap.unwrap(verifyBytes, opts.newPassphrase); }
269
269
  catch (e) {
270
- try { fs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
270
+ try { nodeFs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
271
271
  throw new VaultPassphraseError("vault-passphrase/verify-failed",
272
272
  "round-trip with new passphrase failed: " + ((e && e.message) || String(e)) +
273
273
  " — " + SEALED_NAME + " is UNCHANGED");
274
274
  }
275
275
  if (Buffer.compare(verifyPlain, plainBytes) !== 0) {
276
- try { fs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
276
+ try { nodeFs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
277
277
  throw new VaultPassphraseError("vault-passphrase/verify-mismatch",
278
278
  "rotated sealed file decrypts under new passphrase but to different bytes — " +
279
279
  SEALED_NAME + " is UNCHANGED. Filesystem may be faulty.");
@@ -283,7 +283,7 @@ async function rotate(opts) {
283
283
  // input unchanged — refuse to commit.
284
284
  try {
285
285
  await vaultWrap.unwrap(verifyBytes, opts.oldPassphrase);
286
- try { fs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
286
+ try { nodeFs.unlinkSync(p.sealedTmp); } catch (_e) { /* cleanup */ }
287
287
  throw new VaultPassphraseError("vault-passphrase/rotate-noop",
288
288
  "old passphrase still unwraps the new sealed bytes — rotation did not take effect");
289
289
  } catch (e) {
@@ -292,7 +292,7 @@ async function rotate(opts) {
292
292
  }
293
293
 
294
294
  // Step 3: atomic rename — swap in the new sealed file
295
- fs.renameSync(p.sealedTmp, p.sealed);
295
+ nodeFs.renameSync(p.sealedTmp, p.sealed);
296
296
  atomicFile.fsyncDir(opts.dataDir);
297
297
 
298
298
  return { sealedPath: p.sealed };
@@ -23,7 +23,7 @@
23
23
  * exposure to later env-dump surfaces. This doesn't zero the memory
24
24
  * (JavaScript can't) but does remove the env-object reference.
25
25
  */
26
- var fs = require("fs");
26
+ var nodeFs = require("fs");
27
27
  var readline = require("readline");
28
28
  var safeEnv = require("../parsers/safe-env");
29
29
  var safeBuffer = require("../safe-buffer");
@@ -83,7 +83,7 @@ async function fromFile(filePath, opts) {
83
83
  }
84
84
  var raw;
85
85
  try {
86
- raw = fs.readFileSync(filePath);
86
+ raw = nodeFs.readFileSync(filePath);
87
87
  } catch (e) {
88
88
  throw new Error("failed to read " + envVars.file + " (" + filePath + "): " + e.code);
89
89
  }