@blamejs/core 0.18.54 → 0.18.56

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 (48) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/NOTICE +5 -5
  3. package/README.md +9 -9
  4. package/lib/agent-audit.js +27 -2
  5. package/lib/audit-sign.js +24 -5
  6. package/lib/audit.js +26 -24
  7. package/lib/auth/passkey.js +4 -1
  8. package/lib/chain-writer.js +17 -0
  9. package/lib/db-file-lifecycle.js +14 -3
  10. package/lib/db.js +505 -49
  11. package/lib/guard-filename.js +8 -1
  12. package/lib/guard-html.js +10 -2
  13. package/lib/guard-list-unsubscribe.js +6 -1
  14. package/lib/guard-managesieve-command.js +24 -3
  15. package/lib/guard-smtp-command.js +20 -4
  16. package/lib/guard-svg.js +6 -1
  17. package/lib/http-client.js +17 -3
  18. package/lib/mail-agent.js +6 -4
  19. package/lib/mail-auth.js +59 -2
  20. package/lib/mail-server-imap.js +65 -34
  21. package/lib/mail-server-managesieve.js +65 -42
  22. package/lib/mail-server-mx.js +313 -40
  23. package/lib/mail-server-net.js +155 -1
  24. package/lib/mail-server-pop3.js +16 -19
  25. package/lib/mail-server-rate-limit.js +104 -6
  26. package/lib/mail-server-submission.js +162 -33
  27. package/lib/mail-server-tls.js +71 -11
  28. package/lib/mcp.js +11 -3
  29. package/lib/middleware/csrf-protect.js +37 -20
  30. package/lib/middleware/require-mtls.js +8 -1
  31. package/lib/network-tls.js +18 -0
  32. package/lib/safe-mount-info.js +39 -6
  33. package/lib/safe-smtp.js +96 -1
  34. package/lib/safe-url.js +8 -2
  35. package/lib/self-update.js +4 -1
  36. package/lib/session-stores.js +6 -3
  37. package/lib/vendor/MANIFEST.json +34 -34
  38. package/lib/vendor/blamejs-pki.cjs +396 -37
  39. package/lib/vendor/browser/noble-ciphers.mjs +15 -1
  40. package/lib/vendor/browser/noble-hashes.mjs +12 -4
  41. package/lib/vendor/browser/noble-post-quantum.mjs +78 -37
  42. package/lib/vendor/noble-ciphers.cjs +15 -1
  43. package/lib/vendor/noble-curves.cjs +46 -21
  44. package/lib/vendor/noble-post-quantum.cjs +184 -75
  45. package/lib/watcher.js +31 -6
  46. package/lib/ws-client.js +17 -2
  47. package/package.json +1 -1
  48. package/sbom.cdx.json +6 -6
@@ -81,6 +81,22 @@ var SafeMountInfoError = defineClass("SafeMountInfoError", { alwaysPermanent: tr
81
81
 
82
82
  var DEFAULT_PATH = "/proc/self/mountinfo";
83
83
 
84
+ // The default path is a Linux path, and reaching for it anywhere else is not
85
+ // merely useless. A leading slash is DRIVE-relative on Windows, so the read
86
+ // lands on C:\proc\self\mountinfo — a location an unprivileged local user can
87
+ // create, because the default ACL on C:\ grants Authenticated Users the right
88
+ // to add subdirectories. Whoever plants that file authors the entries
89
+ // bestMatch() and isBindMount() answer from, which is to say they choose what
90
+ // the framework believes about which filesystem a path is on.
91
+ //
92
+ // So off Linux there is no default: a caller who genuinely has a mountinfo
93
+ // file elsewhere still passes opts.path, and everyone else is refused rather
94
+ // than answered from a file anyone could have written. Platform is a parameter
95
+ // so the Windows branch is reachable from a Linux CI host.
96
+ function _defaultPathFor(platform) {
97
+ return platform === "linux" ? DEFAULT_PATH : null;
98
+ }
99
+
84
100
  /**
85
101
  * @primitive b.safeMountInfo.parse
86
102
  * @signature b.safeMountInfo.parse(text, opts?)
@@ -187,12 +203,20 @@ function parse(text, opts) {
187
203
  * @related b.safeMountInfo.parse, b.safeMountInfo.bestMatch
188
204
  *
189
205
  * Read + parse `/proc/self/mountinfo` in one call. Returns the same
190
- * array shape as `parse(text)`. On non-Linux platforms (where /proc
191
- * doesn't exist) returns `opts.fallback` (default `null`); audit
192
- * emission per `safe-mount-info.refused` with code `read-failed`.
206
+ * array shape as `parse(text)`.
207
+ *
208
+ * The default path is used on Linux only. Elsewhere there is no default and
209
+ * `opts.fallback` (default `null`) is returned without reading anything, with
210
+ * an audit emission of `safe-mount-info.refused` carrying code
211
+ * `no-default-path`. `/proc` is not simply absent off Linux — a leading slash
212
+ * is drive-relative on Windows, so the default names `C:\proc\self\mountinfo`,
213
+ * which an unprivileged local user can create; reading it would let whoever
214
+ * wrote it decide which filesystem a path appears to be on. A caller holding a
215
+ * mountinfo file elsewhere passes `opts.path`, which is honored on every
216
+ * platform and reports a read failure as `read-failed`.
193
217
  *
194
218
  * @opts
195
- * path: string, // override path (default /proc/self/mountinfo)
219
+ * path: string, // override path; on Linux defaults to /proc/self/mountinfo, elsewhere there is no default
196
220
  * fallback: any, // returned on read failure (default null)
197
221
  * audit: object, // optional b.audit handle for refusal events
198
222
  * strict: boolean, // forwarded to parse()
@@ -211,12 +235,20 @@ function read(opts) {
211
235
  "safeMountInfo.read");
212
236
  var path = typeof opts.path === "string" && opts.path.length > 0
213
237
  ? opts.path
214
- : DEFAULT_PATH;
238
+ : _defaultPathFor(process.platform);
239
+ if (!path) {
240
+ _refuseEmit(opts, "safe-mount-info/no-default-path",
241
+ "/proc/self/mountinfo is a Linux path and this host is " + process.platform +
242
+ " — pass opts.path to name a mountinfo file explicitly.");
243
+ return ("fallback" in opts) ? opts.fallback : null;
244
+ }
215
245
  var text;
216
246
  try { text = nodeFs.readFileSync(path, "utf8"); }
217
247
  catch (e) {
248
+ // Name the file that was actually read. A caller who passed opts.path and
249
+ // is told "/proc/self/mountinfo unreadable" is looking at the wrong file.
218
250
  _refuseEmit(opts, "safe-mount-info/read-failed",
219
- "/proc/self/mountinfo unreadable: " + ((e && e.message) || String(e)));
251
+ path + " unreadable: " + ((e && e.message) || String(e)));
220
252
  return ("fallback" in opts) ? opts.fallback : null;
221
253
  }
222
254
  return parse(text, opts);
@@ -305,4 +337,5 @@ module.exports = {
305
337
  isBindMount: isBindMount,
306
338
  SafeMountInfoError: SafeMountInfoError,
307
339
  DEFAULT_PATH: DEFAULT_PATH,
340
+ _defaultPathForForTest: _defaultPathFor,
308
341
  };
package/lib/safe-smtp.js CHANGED
@@ -39,6 +39,7 @@
39
39
  */
40
40
 
41
41
  var { defineClass } = require("./framework-error");
42
+ var guardSmtpCommand = require("./guard-smtp-command");
42
43
 
43
44
  var SafeSmtpError = defineClass("SafeSmtpError", { alwaysPermanent: true });
44
45
 
@@ -110,7 +111,14 @@ function dotUnstuff(buf) {
110
111
  }
111
112
  var out = Buffer.alloc(buf.length);
112
113
  var oi = 0;
113
- for (var i = 0; i < buf.length; i += 1) {
114
+ // Offset 0 IS a line start. RFC 5321 §4.5.2 has the sender stuff a leading
115
+ // dot on any line of the body and grants the first line no exemption, but
116
+ // this only ever looked for a dot AFTER a CRLF — so a body beginning
117
+ // `..signature` was delivered with the extra dot still on it, and dotStuff,
118
+ // which does stuff offset 0, had a pair that would not undo it.
119
+ var start = 0;
120
+ if (buf.length >= 2 && buf[0] === 0x2e && buf[1] === 0x2e) start = 1;
121
+ for (var i = start; i < buf.length; i += 1) {
114
122
  out[oi++] = buf[i];
115
123
  // After \r\n, if the next byte is `.` followed by another non-CR
116
124
  // byte (i.e., not the terminator itself), strip the stuffing dot.
@@ -179,9 +187,96 @@ function dotStuff(buf) {
179
187
  return out.subarray(0, oi);
180
188
  }
181
189
 
190
+ /**
191
+ * @primitive b.safeSmtp.createBodyScanner
192
+ * @signature b.safeSmtp.createBodyScanner()
193
+ * @since 0.18.55
194
+ * @status stable
195
+ * @related b.safeSmtp.findDotTerminator, b.guardSmtpCommand.detectBodySmuggling
196
+ *
197
+ * Watch a DATA body for its terminator and for the smuggling shape as it
198
+ * ARRIVES, in work proportional to each chunk rather than to everything
199
+ * received so far.
200
+ *
201
+ * A listener that answers "has the body ended yet?" by re-deriving the whole
202
+ * accumulated buffer on every chunk does O(n) work per chunk and O(n²) over the
203
+ * message. The byte cap still holds — the collector refuses a chunk that would
204
+ * cross it — but processor cost is not what a byte cap bounds, so a message
205
+ * inside the limit could still cost minutes. Measured before this existed:
206
+ * 1 MiB accepted in 143 ms and 8 MiB in 4949 ms, a growth of 4.67x for each
207
+ * doubling where linear would hold at 2.
208
+ *
209
+ * Each `push` scans only the new bytes plus a four-byte overlap from the
210
+ * previous chunk. Four is exact, not generous: the longest shape either screen
211
+ * matches spans five bytes (`\r\n.\r\n`, and the smuggling scan's widest
212
+ * lookahead), and a pattern of length L needs L-1 bytes of overlap to be caught
213
+ * across a boundary.
214
+ *
215
+ * @example
216
+ * var scan = b.safeSmtp.createBodyScanner();
217
+ * var seen = scan.push(chunk);
218
+ * if (seen.smuggling) refuse();
219
+ * if (seen.terminatorAt !== -1) finish(collector.result(), seen.terminatorAt);
220
+ */
221
+ function createBodyScanner() {
222
+ var OVERLAP = 4; // longest matched shape (5) minus one
223
+ var consumed = 0; // bytes pushed before the current chunk
224
+ var tail = Buffer.alloc(0); // last OVERLAP bytes of what came before
225
+ var sawSmuggling = false;
226
+ var terminatorAt = -1;
227
+ // The byte immediately before `tail`, which the next window will not contain.
228
+ // Classifying a leading LF needs it: overlap gives every other offset its
229
+ // predecessor, but never offset zero, and widening the overlap only changes
230
+ // which byte is stranded there.
231
+ var beforeTail = -1;
232
+
233
+ return {
234
+ push: function (chunk) {
235
+ if (!Buffer.isBuffer(chunk)) {
236
+ throw new SafeSmtpError("safe-smtp/bad-input",
237
+ "createBodyScanner.push: chunk must be a Buffer");
238
+ }
239
+ // Once a verdict is reached it stands: the terminator does not move and a
240
+ // smuggling shape does not un-happen. Later chunks are still counted so
241
+ // the reported offset stays absolute.
242
+ var window = tail.length === 0 ? chunk : Buffer.concat([tail, chunk]);
243
+ var windowStart = consumed - tail.length;
244
+
245
+ // `windowStart === 0`, NOT `consumed === 0`: with the overlap carried in,
246
+ // a window can still begin at body offset 0 after bytes have been
247
+ // consumed. One-byte chunks are the case — the first push is a lone `.`
248
+ // (too short to match), and the second window is `.\n` starting at 0 with
249
+ // one byte already consumed. Testing `consumed` there skipped the
250
+ // dot-at-body-start shape entirely.
251
+ if (!sawSmuggling &&
252
+ guardSmtpCommand.detectBodySmuggling(window, windowStart === 0,
253
+ beforeTail === 0x0d)) {
254
+ sawSmuggling = true;
255
+ }
256
+ if (terminatorAt === -1) {
257
+ var at = findDotTerminator(window);
258
+ if (at !== -1) terminatorAt = windowStart + at;
259
+ }
260
+
261
+ consumed += chunk.length;
262
+ // Capture the byte the next window will drop off its front, before the
263
+ // window itself goes out of scope. When the window is no longer than the
264
+ // overlap nothing is dropped, and the next window still starts at body
265
+ // offset 0, where there is no preceding byte to carry.
266
+ beforeTail = window.length > OVERLAP ? window[window.length - OVERLAP - 1] : -1;
267
+ tail = window.length <= OVERLAP ? window : window.subarray(window.length - OVERLAP);
268
+ return { smuggling: sawSmuggling, terminatorAt: terminatorAt };
269
+ },
270
+ // What the scanner has been shown, so a caller can check its own accounting
271
+ // against this one rather than keeping a second counter.
272
+ bytesSeen: function () { return consumed; },
273
+ };
274
+ }
275
+
182
276
  module.exports = {
183
277
  findDotTerminator: findDotTerminator,
184
278
  dotUnstuff: dotUnstuff,
185
279
  dotStuff: dotStuff,
280
+ createBodyScanner: createBodyScanner,
186
281
  SafeSmtpError: SafeSmtpError,
187
282
  };
package/lib/safe-url.js CHANGED
@@ -312,7 +312,11 @@ function _normalizePctPath(path) {
312
312
  */
313
313
  function parse(url, opts) {
314
314
  opts = opts || {};
315
- var allowed = Array.isArray(opts.allowedProtocols) && opts.allowedProtocols.length > 0
315
+ // The documented default applies when the option is OMITTED. An explicitly
316
+ // empty list is a caller saying no protocol is acceptable, and widening that
317
+ // back to https: answers "none" with "one" — an allowlist that disappears
318
+ // when empty is a firewall rule set that opens when the last rule is deleted.
319
+ var allowed = Array.isArray(opts.allowedProtocols)
316
320
  ? opts.allowedProtocols
317
321
  : ALLOW_HTTP_TLS;
318
322
  var errClass = opts.errorClass;
@@ -531,7 +535,9 @@ function format(url) {
531
535
  */
532
536
  function canonicalize(input, opts) {
533
537
  opts = opts || {};
534
- var allowedSchemes = Array.isArray(opts.allowedSchemes) && opts.allowedSchemes.length > 0
538
+ // Same reading as parse above: the default is for the OMITTED case. An empty
539
+ // list asked for nothing and used to receive all four schemes.
540
+ var allowedSchemes = Array.isArray(opts.allowedSchemes)
535
541
  ? opts.allowedSchemes
536
542
  : ALLOW_ANY;
537
543
 
@@ -231,7 +231,10 @@ function _validatePollOpts(opts) {
231
231
  throw new SelfUpdateError("selfupdate/bad-releases-url",
232
232
  "selfUpdate.poll: opts.releasesUrl is not parseable as a URL");
233
233
  }
234
- var allowedProtocols = Array.isArray(opts.allowedProtocols) && opts.allowedProtocols.length > 0
234
+ // The documented default is for the OMITTED case. An explicitly empty
235
+ // list says no protocol may be dialled, and widening it back to https:
236
+ // answers "none" with "one".
237
+ var allowedProtocols = Array.isArray(opts.allowedProtocols)
235
238
  ? opts.allowedProtocols.slice() : ["https:"];
236
239
  if (allowedProtocols.indexOf(parsedProto) === -1) {
237
240
  throw new SelfUpdateError("selfupdate/bad-releases-url",
@@ -29,9 +29,12 @@
29
29
  * schema (sidHash PRIMARY KEY, userId, userIdHash, data, createdAt,
30
30
  * expiresAt, lastActivity) plus the indexes session-side queries
31
31
  * need (userIdHash for `destroyAllForUser`, expiresAt for
32
- * `purgeExpired`). Operators typically point `file` at tmpfs (e.g.
33
- * `/dev/shm/blamejs-sessions.db`) so session inserts run RAM-fast
34
- * and don't compete with the main DB's encryption-flush cycle.
32
+ * `purgeExpired`). Operators typically point `file` at tmpfs
33
+ * (`/dev/shm/blamejs-sessions.db` on Linux, an in-memory volume on
34
+ * Windows) so session inserts run RAM-fast and don't compete with
35
+ * the main DB's encryption-flush cycle. The path is yours to name —
36
+ * a leading slash is drive-relative on Windows, where `/dev/shm`
37
+ * means `C:\dev\shm` and is ordinary disk.
35
38
  *
36
39
  * Wire it once at boot, before the first session call:
37
40
  *
@@ -2,7 +2,7 @@
2
2
  "_comment": "Vendored dependencies — no npm runtime packages. Use scripts/vendor-update.sh to update.",
3
3
  "packages": {
4
4
  "@noble/ciphers": {
5
- "version": "2.3.0",
5
+ "version": "2.4.0",
6
6
  "license": "MIT",
7
7
  "author": "Paul Miller",
8
8
  "source": "https://github.com/paulmillr/noble-ciphers",
@@ -15,16 +15,16 @@
15
15
  "browser": "lib/vendor/browser/noble-ciphers.mjs"
16
16
  },
17
17
  "bundler": "esbuild --format=cjs --platform=node (server), esbuild --format=esm --platform=browser (browser)",
18
- "bundledAt": "2026-08-10T00:00:00Z",
19
- "cpe": "cpe:2.3:a:paulmillr:noble-ciphers:2.3.0:*:*:*:*:node.js:*:*",
18
+ "bundledAt": "2026-08-27T00:00:00Z",
19
+ "cpe": "cpe:2.3:a:paulmillr:noble-ciphers:2.4.0:*:*:*:*:node.js:*:*",
20
20
  "hashes": {
21
- "server": "sha256:f3325f480cb8eb814fcb0baaa19336cbbf2b993f48624c6aa9600ffd69d0be5e",
22
- "browser": "sha256:0ffd91540bcb586a29b56e52ee1c29df69097b50776beb4036a07558f7a4e12e"
21
+ "server": "sha256:acdcf1ba4bde8177cbfcfef22b543022284a1529afb68bc8329303837c8c021e",
22
+ "browser": "sha256:fc422d85a65c5dc1208066b0156e100c4790be3c8791f644b80524c25d4bc3ee"
23
23
  },
24
- "refreshedAt": "2026-08-24T23:54:10.282Z"
24
+ "refreshedAt": "2026-08-28T04:49:21.011Z"
25
25
  },
26
26
  "@noble/hashes": {
27
- "version": "2.3.0",
27
+ "version": "2.4.0",
28
28
  "license": "MIT",
29
29
  "author": "Paul Miller",
30
30
  "source": "https://github.com/paulmillr/noble-hashes",
@@ -43,15 +43,15 @@
43
43
  "browser": "lib/vendor/browser/noble-hashes.mjs"
44
44
  },
45
45
  "bundler": "esbuild --format=esm --platform=browser (browser only)",
46
- "bundledAt": "2026-08-10T00:00:00Z",
47
- "cpe": "cpe:2.3:a:paulmillr:noble-hashes:2.3.0:*:*:*:*:node.js:*:*",
46
+ "bundledAt": "2026-08-27T00:00:00Z",
47
+ "cpe": "cpe:2.3:a:paulmillr:noble-hashes:2.4.0:*:*:*:*:node.js:*:*",
48
48
  "hashes": {
49
- "browser": "sha256:dfe4b7ae3c9880e388c8da4b68f44742b229b53afacd1e674179527e33da62b0"
49
+ "browser": "sha256:0e135cbb496a1b7d15bf36b8c611a8feaad49ced60a03bf916bada78b589aa66"
50
50
  },
51
- "refreshedAt": "2026-08-24T23:54:10.282Z"
51
+ "refreshedAt": "2026-08-28T04:49:21.011Z"
52
52
  },
53
53
  "@noble/curves": {
54
- "version": "2.3.0",
54
+ "version": "2.4.0",
55
55
  "license": "MIT",
56
56
  "author": "Paul Miller",
57
57
  "source": "https://github.com/paulmillr/noble-curves",
@@ -65,21 +65,21 @@
65
65
  "server": "lib/vendor/noble-curves.cjs"
66
66
  },
67
67
  "bundler": "esbuild --format=cjs --platform=node",
68
- "bundledAt": "2026-08-21T00:00:00Z",
69
- "cpe": "cpe:2.3:a:paulmillr:noble-curves:2.3.0:*:*:*:*:node.js:*:*",
68
+ "bundledAt": "2026-08-27T00:00:00Z",
69
+ "cpe": "cpe:2.3:a:paulmillr:noble-curves:2.4.0:*:*:*:*:node.js:*:*",
70
70
  "hashes": {
71
- "server": "sha256:b5fe88d1ea780d0581dee6145d666f89d46fc9531b5db35db2e5b16627840890"
71
+ "server": "sha256:477359f445eed241ad4ededb84921483c3c97618a160ef78b74bb1a421c17da7"
72
72
  },
73
- "refreshedAt": "2026-08-24T23:54:10.282Z",
73
+ "refreshedAt": "2026-08-28T04:49:21.011Z",
74
74
  "components": {
75
75
  "@noble/hashes": {
76
76
  "url": "https://github.com/paulmillr/noble-hashes",
77
- "version": "2.3.0"
77
+ "version": "2.4.0"
78
78
  }
79
79
  }
80
80
  },
81
81
  "@noble/post-quantum": {
82
- "version": "0.7.0",
82
+ "version": "0.7.1",
83
83
  "license": "MIT",
84
84
  "author": "Paul Miller",
85
85
  "source": "https://github.com/paulmillr/noble-post-quantum",
@@ -108,25 +108,25 @@
108
108
  "browser": "lib/vendor/browser/noble-post-quantum.mjs"
109
109
  },
110
110
  "bundler": "esbuild --format=cjs --platform=node (server), esbuild --format=esm --platform=browser (browser)",
111
- "bundledAt": "2026-08-10T00:00:00Z",
112
- "cpe": "cpe:2.3:a:paulmillr:noble-post-quantum:0.7.0:*:*:*:*:node.js:*:*",
111
+ "bundledAt": "2026-08-27T00:00:00Z",
112
+ "cpe": "cpe:2.3:a:paulmillr:noble-post-quantum:0.7.1:*:*:*:*:node.js:*:*",
113
113
  "hashes": {
114
- "server": "sha256:fab7ebe5737793862c473444f4ee5912f79dd1edec86683acbb4eecbca0f5892",
115
- "browser": "sha256:cae1d5bbdc7184b202b6ca68df6e1db7b0d0f668c77809ded189ca7f271accc9"
114
+ "server": "sha256:04eaaa4838b43162912c851dd2cab52ab82f56decad8542934171247017a6893",
115
+ "browser": "sha256:30ceef750bc57ae5f59c5aa7454eafb7aad55d30c261a1b5c538a66c569fc031"
116
116
  },
117
- "refreshedAt": "2026-08-24T23:54:10.282Z",
117
+ "refreshedAt": "2026-08-28T04:49:21.011Z",
118
118
  "components": {
119
119
  "@noble/hashes": {
120
120
  "url": "https://github.com/paulmillr/noble-hashes",
121
- "version": "2.3.0"
121
+ "version": "2.4.0"
122
122
  },
123
123
  "@noble/curves": {
124
124
  "url": "https://github.com/paulmillr/noble-curves",
125
- "version": "2.3.0"
125
+ "version": "2.4.0"
126
126
  },
127
127
  "@noble/ciphers": {
128
128
  "url": "https://github.com/paulmillr/noble-ciphers",
129
- "version": "2.3.0"
129
+ "version": "2.4.0"
130
130
  }
131
131
  }
132
132
  },
@@ -148,7 +148,7 @@
148
148
  },
149
149
  "runtime_artifact": "lib/vendor/common-passwords-top-10000.data.js",
150
150
  "integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
151
- "refreshedAt": "2026-08-24T23:54:10.282Z"
151
+ "refreshedAt": "2026-08-28T04:49:21.011Z"
152
152
  },
153
153
  "bimi-trust-anchors": {
154
154
  "version": "operator-managed",
@@ -173,7 +173,7 @@
173
173
  },
174
174
  "runtime_artifact": "lib/vendor/bimi-trust-anchors.data.js",
175
175
  "integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
176
- "refreshedAt": "2026-08-24T23:54:10.282Z"
176
+ "refreshedAt": "2026-08-28T04:49:21.011Z"
177
177
  },
178
178
  "publicsuffix-list": {
179
179
  "version": "master",
@@ -193,10 +193,10 @@
193
193
  },
194
194
  "runtime_artifact": "lib/vendor/public-suffix-list.data.js",
195
195
  "integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
196
- "refreshedAt": "2026-08-24T23:54:10.282Z"
196
+ "refreshedAt": "2026-08-28T04:49:21.011Z"
197
197
  },
198
198
  "@blamejs/pki": {
199
- "version": "0.5.30",
199
+ "version": "0.5.31",
200
200
  "license": "Apache-2.0",
201
201
  "author": "blamejs",
202
202
  "source": "https://github.com/blamejs/pki",
@@ -216,12 +216,12 @@
216
216
  "server": "lib/vendor/blamejs-pki.cjs"
217
217
  },
218
218
  "bundler": "esbuild --format=cjs --platform=node --external:crypto --external:node:crypto",
219
- "bundledAt": "2026-08-24T00:00:00Z",
220
- "cpe": "cpe:2.3:a:blamejs:pki:0.5.30:*:*:*:*:node.js:*:*",
219
+ "bundledAt": "2026-08-25T00:00:00Z",
220
+ "cpe": "cpe:2.3:a:blamejs:pki:0.5.31:*:*:*:*:node.js:*:*",
221
221
  "hashes": {
222
- "server": "sha256:fc8b1783ae40c377c1bc7afb7bd902b5282c165ed11354b803867f7d9f75f021"
222
+ "server": "sha256:8cc54fdfb7ac5277fb30f054f57500a9e77ce6b2d2b8f6846a14766d217770db"
223
223
  },
224
- "refreshedAt": "2026-08-24T23:54:10.282Z"
224
+ "refreshedAt": "2026-08-28T04:49:21.011Z"
225
225
  }
226
226
  }
227
227
  }