@blamejs/core 0.15.12 → 0.15.14

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 (365) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/index.js +2 -0
  3. package/lib/a2a-tasks.js +45 -29
  4. package/lib/acme.js +6 -5
  5. package/lib/agent-event-bus.js +18 -4
  6. package/lib/agent-idempotency.js +7 -6
  7. package/lib/agent-orchestrator.js +2 -5
  8. package/lib/agent-saga.js +3 -5
  9. package/lib/agent-snapshot.js +32 -2
  10. package/lib/agent-tenant.js +2 -5
  11. package/lib/ai-adverse-decision.js +2 -15
  12. package/lib/ai-aedt-bias-audit.js +2 -1
  13. package/lib/ai-capability.js +1 -6
  14. package/lib/ai-content-detect.js +1 -3
  15. package/lib/ai-dp.js +1 -5
  16. package/lib/ai-frontier-protocol.js +1 -1
  17. package/lib/ai-input.js +2 -2
  18. package/lib/ai-model-manifest.js +1 -1
  19. package/lib/ai-output.js +16 -7
  20. package/lib/ai-pref.js +3 -8
  21. package/lib/ai-quota.js +3 -14
  22. package/lib/api-key.js +37 -28
  23. package/lib/api-snapshot.js +4 -1
  24. package/lib/app-shutdown.js +7 -1
  25. package/lib/archive-adapters.js +2 -4
  26. package/lib/archive-entry-policy.js +32 -0
  27. package/lib/archive-gz.js +9 -0
  28. package/lib/archive-read.js +14 -24
  29. package/lib/archive-tar-read.js +56 -24
  30. package/lib/archive.js +6 -12
  31. package/lib/arg-parser.js +7 -6
  32. package/lib/asn1-der.js +70 -22
  33. package/lib/asyncapi-traits.js +2 -6
  34. package/lib/atomic-file.js +312 -33
  35. package/lib/audit-chain.js +183 -54
  36. package/lib/audit-daily-review.js +36 -16
  37. package/lib/audit-emit.js +82 -0
  38. package/lib/audit-sign.js +258 -0
  39. package/lib/audit-tools.js +108 -23
  40. package/lib/audit.js +91 -2
  41. package/lib/auth/access-lock.js +7 -29
  42. package/lib/auth/bot-challenge.js +1 -1
  43. package/lib/auth/ciba.js +43 -4
  44. package/lib/auth/dpop.js +29 -36
  45. package/lib/auth/fido-mds3.js +14 -16
  46. package/lib/auth/jwt-external.js +26 -8
  47. package/lib/auth/jwt.js +15 -17
  48. package/lib/auth/lockout.js +24 -27
  49. package/lib/auth/oauth.js +67 -45
  50. package/lib/auth/oid4vci.js +55 -32
  51. package/lib/auth/oid4vp.js +3 -2
  52. package/lib/auth/openid-federation.js +6 -6
  53. package/lib/auth/passkey.js +4 -4
  54. package/lib/auth/password.js +8 -2
  55. package/lib/auth/saml.js +70 -40
  56. package/lib/auth/sd-jwt-vc-holder.js +2 -14
  57. package/lib/auth/sd-jwt-vc-issuer.js +2 -14
  58. package/lib/auth/sd-jwt-vc.js +25 -5
  59. package/lib/auth/status-list.js +21 -9
  60. package/lib/auth/step-up.js +15 -13
  61. package/lib/auth-bot-challenge.js +27 -39
  62. package/lib/backup/bundle.js +18 -20
  63. package/lib/backup/crypto.js +23 -8
  64. package/lib/backup/index.js +55 -67
  65. package/lib/backup/manifest.js +7 -1
  66. package/lib/bounded-map.js +112 -1
  67. package/lib/breach-deadline.js +1 -11
  68. package/lib/break-glass.js +41 -22
  69. package/lib/cache.js +7 -18
  70. package/lib/cbor.js +36 -12
  71. package/lib/cdn-cache-control.js +15 -12
  72. package/lib/cert.js +8 -13
  73. package/lib/chain-writer.js +162 -47
  74. package/lib/cli.js +10 -2
  75. package/lib/client-hints.js +7 -9
  76. package/lib/cloud-events.js +43 -33
  77. package/lib/cluster-storage.js +9 -41
  78. package/lib/cms-codec.js +2 -1
  79. package/lib/codepoint-class.js +84 -1
  80. package/lib/compliance-ai-act-logging.js +1 -6
  81. package/lib/compliance-ai-act-transparency.js +2 -4
  82. package/lib/compliance-eaa.js +2 -12
  83. package/lib/compliance-sanctions-fetcher.js +21 -28
  84. package/lib/compliance-sanctions.js +11 -21
  85. package/lib/compliance.js +3 -10
  86. package/lib/config-drift.js +24 -20
  87. package/lib/content-credentials.js +11 -8
  88. package/lib/content-digest.js +21 -12
  89. package/lib/cookies.js +15 -13
  90. package/lib/cose.js +39 -11
  91. package/lib/cra-report.js +1 -11
  92. package/lib/crdt.js +2 -1
  93. package/lib/crypto-field.js +34 -33
  94. package/lib/crypto.js +138 -7
  95. package/lib/csp.js +239 -3
  96. package/lib/daemon.js +46 -42
  97. package/lib/data-act.js +46 -13
  98. package/lib/db-file-lifecycle.js +14 -6
  99. package/lib/db-query.js +75 -49
  100. package/lib/db.js +66 -27
  101. package/lib/dbsc.js +5 -6
  102. package/lib/ddl-change-control.js +18 -14
  103. package/lib/deprecate.js +4 -5
  104. package/lib/did.js +6 -2
  105. package/lib/dora.js +43 -13
  106. package/lib/dr-runbook.js +1 -1
  107. package/lib/dsa.js +2 -1
  108. package/lib/dsr.js +30 -20
  109. package/lib/early-hints.js +19 -0
  110. package/lib/eat.js +5 -1
  111. package/lib/external-db-migrate.js +21 -22
  112. package/lib/external-db.js +74 -30
  113. package/lib/fda-21cfr11.js +42 -13
  114. package/lib/fdx.js +22 -18
  115. package/lib/file-upload.js +80 -66
  116. package/lib/flag-evaluation-context.js +5 -8
  117. package/lib/flag-providers.js +6 -2
  118. package/lib/forms.js +1 -1
  119. package/lib/framework-error.js +12 -0
  120. package/lib/framework-schema.js +19 -0
  121. package/lib/fsm.js +7 -12
  122. package/lib/gate-contract.js +911 -39
  123. package/lib/gdpr-ropa.js +22 -22
  124. package/lib/graphql-federation.js +18 -5
  125. package/lib/guard-agent-registry.js +2 -1
  126. package/lib/guard-all.js +3 -2
  127. package/lib/guard-archive.js +9 -30
  128. package/lib/guard-auth.js +23 -80
  129. package/lib/guard-cidr.js +20 -96
  130. package/lib/guard-csv.js +135 -196
  131. package/lib/guard-domain.js +23 -106
  132. package/lib/guard-dsn.js +17 -14
  133. package/lib/guard-email.js +46 -53
  134. package/lib/guard-envelope.js +2 -2
  135. package/lib/guard-event-bus-topic.js +2 -1
  136. package/lib/guard-filename.js +12 -60
  137. package/lib/guard-graphql.js +28 -75
  138. package/lib/guard-html-wcag.js +15 -2
  139. package/lib/guard-html.js +74 -128
  140. package/lib/guard-idempotency-key.js +2 -1
  141. package/lib/guard-image.js +280 -77
  142. package/lib/guard-imap-command.js +9 -10
  143. package/lib/guard-jmap.js +1 -1
  144. package/lib/guard-json.js +101 -109
  145. package/lib/guard-jsonpath.js +20 -88
  146. package/lib/guard-jwt.js +32 -114
  147. package/lib/guard-list-id.js +2 -7
  148. package/lib/guard-list-unsubscribe.js +2 -7
  149. package/lib/guard-mail-compose.js +5 -6
  150. package/lib/guard-mail-move.js +3 -2
  151. package/lib/guard-mail-query.js +5 -3
  152. package/lib/guard-mail-sieve.js +6 -7
  153. package/lib/guard-managesieve-command.js +6 -5
  154. package/lib/guard-markdown.js +76 -110
  155. package/lib/guard-message-id.js +5 -6
  156. package/lib/guard-mime.js +20 -99
  157. package/lib/guard-oauth.js +19 -73
  158. package/lib/guard-pdf.js +65 -72
  159. package/lib/guard-pop3-command.js +13 -14
  160. package/lib/guard-posture-chain.js +2 -1
  161. package/lib/guard-regex.js +24 -99
  162. package/lib/guard-saga-config.js +2 -1
  163. package/lib/guard-shell.js +22 -87
  164. package/lib/guard-smtp-command.js +9 -12
  165. package/lib/guard-sql.js +15 -13
  166. package/lib/guard-stream-args.js +2 -1
  167. package/lib/guard-svg.js +103 -149
  168. package/lib/guard-template.js +23 -80
  169. package/lib/guard-tenant-id.js +2 -1
  170. package/lib/guard-text.js +592 -0
  171. package/lib/guard-time.js +27 -95
  172. package/lib/guard-uuid.js +21 -93
  173. package/lib/guard-xml.js +76 -106
  174. package/lib/guard-yaml.js +24 -60
  175. package/lib/html-balance.js +7 -3
  176. package/lib/http-client-cache.js +5 -12
  177. package/lib/http-client-cookie-jar.js +35 -16
  178. package/lib/http-client.js +233 -74
  179. package/lib/http-message-signature.js +3 -2
  180. package/lib/i18n-messageformat.js +5 -7
  181. package/lib/i18n.js +83 -26
  182. package/lib/iab-tcf.js +3 -2
  183. package/lib/importmap-integrity.js +41 -1
  184. package/lib/inbox.js +8 -8
  185. package/lib/incident-report.js +12 -27
  186. package/lib/ip-utils.js +49 -6
  187. package/lib/jobs.js +3 -2
  188. package/lib/json-patch.js +1 -1
  189. package/lib/json-path.js +24 -3
  190. package/lib/jtd.js +2 -2
  191. package/lib/keychain.js +6 -18
  192. package/lib/legal-hold.js +30 -23
  193. package/lib/log-stream-cloudwatch.js +44 -112
  194. package/lib/log-stream-otlp-grpc.js +17 -14
  195. package/lib/log-stream-otlp.js +16 -80
  196. package/lib/log-stream-webhook.js +20 -92
  197. package/lib/log.js +2 -2
  198. package/lib/mail-agent.js +2 -2
  199. package/lib/mail-arc-sign.js +8 -3
  200. package/lib/mail-arf.js +4 -3
  201. package/lib/mail-auth.js +43 -69
  202. package/lib/mail-bimi.js +35 -55
  203. package/lib/mail-bounce.js +3 -3
  204. package/lib/mail-crypto-pgp.js +3 -2
  205. package/lib/mail-crypto-smime.js +71 -6
  206. package/lib/mail-dav.js +8 -35
  207. package/lib/mail-deploy.js +15 -14
  208. package/lib/mail-dkim.js +19 -38
  209. package/lib/mail-greylist.js +17 -30
  210. package/lib/mail-helo.js +4 -7
  211. package/lib/mail-journal.js +13 -9
  212. package/lib/mail-mdn.js +12 -7
  213. package/lib/mail-rbl.js +7 -12
  214. package/lib/mail-scan.js +5 -7
  215. package/lib/mail-send-deliver.js +33 -20
  216. package/lib/mail-server-imap.js +32 -87
  217. package/lib/mail-server-jmap.js +39 -52
  218. package/lib/mail-server-managesieve.js +29 -83
  219. package/lib/mail-server-mx.js +33 -74
  220. package/lib/mail-server-net.js +177 -0
  221. package/lib/mail-server-pop3.js +30 -83
  222. package/lib/mail-server-rate-limit.js +30 -6
  223. package/lib/mail-server-registry.js +1 -1
  224. package/lib/mail-server-submission.js +34 -73
  225. package/lib/mail-server-tls.js +98 -2
  226. package/lib/mail-spam-score.js +9 -12
  227. package/lib/mail-store-fts.js +1 -1
  228. package/lib/mail-store.js +3 -2
  229. package/lib/mail.js +28 -13
  230. package/lib/markup-escape.js +31 -0
  231. package/lib/markup-tokenizer.js +78 -0
  232. package/lib/mcp-tool-registry.js +26 -23
  233. package/lib/mcp.js +7 -5
  234. package/lib/mdoc.js +36 -14
  235. package/lib/metrics.js +46 -33
  236. package/lib/middleware/age-gate.js +3 -23
  237. package/lib/middleware/api-encrypt.js +13 -24
  238. package/lib/middleware/assetlinks.js +2 -7
  239. package/lib/middleware/bearer-auth.js +2 -1
  240. package/lib/middleware/body-parser.js +41 -52
  241. package/lib/middleware/bot-disclose.js +7 -10
  242. package/lib/middleware/bot-guard.js +28 -28
  243. package/lib/middleware/clear-site-data.js +5 -1
  244. package/lib/middleware/compression.js +9 -0
  245. package/lib/middleware/cors.js +32 -23
  246. package/lib/middleware/csrf-protect.js +73 -23
  247. package/lib/middleware/daily-byte-quota.js +12 -30
  248. package/lib/middleware/deny-response.js +19 -1
  249. package/lib/middleware/fetch-metadata.js +35 -4
  250. package/lib/middleware/idempotency-key.js +4 -20
  251. package/lib/middleware/network-allowlist.js +61 -30
  252. package/lib/middleware/rate-limit.js +45 -44
  253. package/lib/middleware/scim-server.js +5 -3
  254. package/lib/middleware/security-headers.js +33 -7
  255. package/lib/middleware/security-txt.js +2 -6
  256. package/lib/middleware/speculation-rules.js +6 -3
  257. package/lib/middleware/tus-upload.js +14 -29
  258. package/lib/middleware/web-app-manifest.js +2 -7
  259. package/lib/migrations.js +4 -13
  260. package/lib/mime-parse.js +34 -17
  261. package/lib/module-loader.js +44 -0
  262. package/lib/money.js +105 -0
  263. package/lib/mtls-ca.js +125 -41
  264. package/lib/network-byte-quota.js +4 -18
  265. package/lib/network-dane.js +8 -6
  266. package/lib/network-dns-resolver.js +98 -7
  267. package/lib/network-dns.js +9 -2
  268. package/lib/network-dnssec.js +18 -17
  269. package/lib/network-heartbeat.js +3 -2
  270. package/lib/network-smtp-policy.js +52 -46
  271. package/lib/network-tls.js +67 -47
  272. package/lib/network-tsig.js +2 -2
  273. package/lib/nis2-report.js +2 -12
  274. package/lib/nist-crosswalk.js +1 -1
  275. package/lib/nonce-store.js +81 -3
  276. package/lib/ntp-check.js +28 -0
  277. package/lib/numeric-bounds.js +31 -8
  278. package/lib/object-store/azure-blob-bucket-ops.js +2 -6
  279. package/lib/object-store/azure-blob.js +6 -47
  280. package/lib/object-store/gcs-bucket-ops.js +4 -2
  281. package/lib/object-store/gcs.js +14 -75
  282. package/lib/object-store/http-put.js +2 -7
  283. package/lib/object-store/http-request.js +157 -0
  284. package/lib/object-store/local.js +37 -17
  285. package/lib/object-store/sigv4-bucket-ops.js +2 -1
  286. package/lib/object-store/sigv4.js +10 -79
  287. package/lib/observability-otlp-exporter.js +29 -29
  288. package/lib/observability.js +95 -0
  289. package/lib/openapi-paths-builder.js +7 -3
  290. package/lib/otel-export.js +7 -10
  291. package/lib/outbox.js +54 -41
  292. package/lib/pagination.js +11 -15
  293. package/lib/parsers/safe-env.js +5 -4
  294. package/lib/parsers/safe-ini.js +10 -4
  295. package/lib/parsers/safe-toml.js +11 -9
  296. package/lib/parsers/safe-xml.js +3 -3
  297. package/lib/parsers/safe-yaml.js +28 -9
  298. package/lib/pick.js +63 -5
  299. package/lib/pipl-cn.js +69 -59
  300. package/lib/privacy-pass.js +8 -6
  301. package/lib/problem-details.js +2 -5
  302. package/lib/pubsub.js +4 -8
  303. package/lib/queue-local.js +10 -3
  304. package/lib/redact.js +9 -4
  305. package/lib/render.js +4 -2
  306. package/lib/request-helpers.js +334 -29
  307. package/lib/resource-access-lock.js +3 -3
  308. package/lib/restore-bundle.js +46 -18
  309. package/lib/restore-rollback.js +10 -4
  310. package/lib/restore.js +24 -22
  311. package/lib/retention.js +23 -9
  312. package/lib/router.js +17 -4
  313. package/lib/safe-async.js +457 -0
  314. package/lib/safe-buffer.js +137 -6
  315. package/lib/safe-decompress.js +2 -1
  316. package/lib/safe-dns.js +2 -1
  317. package/lib/safe-ical.js +14 -28
  318. package/lib/safe-icap.js +1 -1
  319. package/lib/safe-json.js +51 -8
  320. package/lib/safe-jsonpath.js +6 -5
  321. package/lib/safe-mime.js +25 -29
  322. package/lib/safe-redirect.js +2 -5
  323. package/lib/safe-schema.js +7 -6
  324. package/lib/safe-sieve.js +1 -1
  325. package/lib/safe-sql.js +126 -0
  326. package/lib/safe-vcard.js +13 -27
  327. package/lib/sandbox-worker.js +15 -2
  328. package/lib/sandbox.js +4 -3
  329. package/lib/scheduler.js +22 -13
  330. package/lib/sec-cyber.js +82 -37
  331. package/lib/seeders.js +4 -11
  332. package/lib/self-update-standalone-verifier.js +16 -0
  333. package/lib/self-update.js +92 -69
  334. package/lib/session-device-binding.js +112 -66
  335. package/lib/session.js +219 -7
  336. package/lib/sql.js +228 -81
  337. package/lib/sse.js +6 -10
  338. package/lib/static.js +201 -111
  339. package/lib/storage.js +4 -2
  340. package/lib/structured-fields.js +275 -16
  341. package/lib/template.js +7 -5
  342. package/lib/tenant-quota.js +53 -38
  343. package/lib/tsa.js +16 -17
  344. package/lib/validate-opts.js +154 -8
  345. package/lib/vault/index.js +5 -0
  346. package/lib/vault/passphrase-ops.js +22 -26
  347. package/lib/vault/passphrase-source.js +8 -3
  348. package/lib/vault/rotate.js +13 -18
  349. package/lib/vault/seal-pem-file.js +34 -49
  350. package/lib/vault-aad.js +3 -2
  351. package/lib/vc.js +3 -8
  352. package/lib/vendor/MANIFEST.json +10 -10
  353. package/lib/vendor/public-suffix-list.dat +23 -10
  354. package/lib/vendor/public-suffix-list.data.js +5498 -5494
  355. package/lib/vex.js +35 -13
  356. package/lib/web-push-vapid.js +23 -20
  357. package/lib/webhook-dispatcher.js +706 -0
  358. package/lib/webhook.js +59 -19
  359. package/lib/websocket-channels.js +9 -7
  360. package/lib/websocket.js +8 -4
  361. package/lib/worm.js +3 -4
  362. package/lib/ws-client.js +65 -56
  363. package/lib/x509-chain.js +44 -0
  364. package/package.json +1 -1
  365. package/sbom.cdx.json +6 -6
@@ -66,6 +66,7 @@
66
66
 
67
67
  var validateOpts = require("../validate-opts");
68
68
  var safeBuffer = require("../safe-buffer");
69
+ var safeJson = require("../safe-json");
69
70
 
70
71
  // Per W3C draft + Chromium implementation. `immediate` triggers the
71
72
  // speculation as soon as the rules are seen; `conservative` waits
@@ -129,7 +130,7 @@ function _validateRules(rules, label) {
129
130
  throw new TypeError(label + "." + actionKey + "[" + ei +
130
131
  "].where must be a `where` clause object (W3C draft, e.g. { href_matches: \"/path/*\" })");
131
132
  }
132
- if (typeof rule.eagerness !== "string" || !EAGERNESS_LEVELS[rule.eagerness]) {
133
+ if (typeof rule.eagerness !== "string" || !Object.prototype.hasOwnProperty.call(EAGERNESS_LEVELS, rule.eagerness)) {
133
134
  throw new TypeError(label + "." + actionKey + "[" + ei +
134
135
  "].eagerness must be one of: " + Object.keys(EAGERNESS_LEVELS).join(", "));
135
136
  }
@@ -245,8 +246,10 @@ function create(opts) {
245
246
  }
246
247
 
247
248
  // Pre-built inline JSON. The body is small (rules objects are
248
- // typically ~200 bytes); JSON.stringify once and cache.
249
- var inlineJson = inline ? JSON.stringify(rulesObj) : null;
249
+ // typically ~200 bytes); stringify once and cache. Uses the
250
+ // <script>-safe serializer so a rules value containing "</script>"
251
+ // (or U+2028/U+2029) cannot break out of the injected element.
252
+ var inlineJson = inline ? safeJson.stringifyForScript(rulesObj) : null;
250
253
 
251
254
  return function speculationRules(req, res, next) {
252
255
  if (!inline) {
@@ -150,10 +150,10 @@ function _parseChecksumHeader(headerValue, allowedSet) {
150
150
  // alphabet); refuse those on the RAW value BEFORE the slice/trim
151
151
  // normalisation (same v0.8.90 trim-before-validate bug class).
152
152
  if (structuredFields.containsControlBytes(headerValue)) return { error: "malformed" };
153
- var sp = headerValue.indexOf(" ");
154
- if (sp === -1) return { error: "malformed" };
155
- var algo = headerValue.slice(0, sp).trim().toLowerCase();
156
- var digestB64 = headerValue.slice(sp + 1).trim();
153
+ var kvp = structuredFields.parseKeyValuePiece(headerValue, " ");
154
+ if (kvp.value === null) return { error: "malformed" };
155
+ var algo = kvp.key;
156
+ var digestB64 = kvp.value.trim();
157
157
  if (algo.length === 0 || digestB64.length === 0) return { error: "malformed" };
158
158
  if (!allowedSet[algo]) return { error: "algo-unsupported" };
159
159
  if (!/^[A-Za-z0-9+/=]+$/.test(digestB64)) return { error: "malformed" };
@@ -311,19 +311,11 @@ function _emitTusBaseHeaders(res, extra) {
311
311
  }
312
312
 
313
313
  function _readChunk(req, maxChunkSize) {
314
- return new Promise(function (resolve, reject) {
315
- var collector = safeBuffer.boundedChunkCollector({
316
- maxBytes: maxChunkSize,
317
- errorClass: TusError,
318
- sizeCode: "tus/chunk-too-large",
319
- sizeMessage: "PATCH body exceeded maxChunkSize",
320
- });
321
- req.on("data", function (c) {
322
- try { collector.push(c); }
323
- catch (e) { req.removeAllListeners("data"); reject(e); }
324
- });
325
- req.on("end", function () { resolve(collector.result()); });
326
- req.on("error", function (e) { reject(e); });
314
+ return safeBuffer.collectStream(req, {
315
+ maxBytes: maxChunkSize,
316
+ errorClass: TusError,
317
+ sizeCode: "tus/chunk-too-large",
318
+ sizeMessage: "PATCH body exceeded maxChunkSize",
327
319
  });
328
320
  }
329
321
 
@@ -388,11 +380,8 @@ function create(opts) {
388
380
  }
389
381
 
390
382
  var store = opts.store;
391
- if (!store || typeof store.create !== "function" || typeof store.head !== "function" ||
392
- typeof store.append !== "function" || typeof store.terminate !== "function") {
393
- throw new TusError("tus/bad-store",
394
- "middleware.tusUpload: store must implement { create, head, append, terminate }");
395
- }
383
+ validateOpts.requireMethods(store, ["create", "head", "append", "terminate"],
384
+ "middleware.tusUpload: store", TusError, "tus/bad-store");
396
385
 
397
386
  var maxSize = opts.maxSize;
398
387
  if (maxSize !== undefined && (typeof maxSize !== "number" || !isFinite(maxSize) || maxSize <= 0)) {
@@ -410,7 +399,7 @@ function create(opts) {
410
399
 
411
400
  var extensions = Array.isArray(opts.extensions) ? opts.extensions.slice() : DEFAULT_EXTENSIONS.slice();
412
401
  for (var i = 0; i < extensions.length; i++) {
413
- if (!KNOWN_EXTENSIONS[extensions[i]]) {
402
+ if (!Object.prototype.hasOwnProperty.call(KNOWN_EXTENSIONS, extensions[i])) {
414
403
  throw new TusError("tus/bad-opts",
415
404
  "middleware.tusUpload: unknown extension '" + extensions[i] + "'");
416
405
  }
@@ -427,7 +416,7 @@ function create(opts) {
427
416
  var checksumAlgorithmSet = {};
428
417
  for (var j = 0; j < checksumAlgorithms.length; j++) {
429
418
  var algo = checksumAlgorithms[j];
430
- if (!KNOWN_CHECKSUM_ALGORITHMS[algo]) {
419
+ if (!Object.prototype.hasOwnProperty.call(KNOWN_CHECKSUM_ALGORITHMS, algo)) {
431
420
  throw new TusError("tus/bad-opts",
432
421
  "middleware.tusUpload: unknown checksum algorithm '" + algo + "'");
433
422
  }
@@ -451,11 +440,7 @@ function create(opts) {
451
440
  return new Date(rec.expireAt).toUTCString();
452
441
  }
453
442
 
454
- function _emitMetric(verb, _outcome, _metadata) {
455
- if (!auditOn) return;
456
- try { observability().safeEvent("middleware.tusUpload." + verb, 1, {}); }
457
- catch (_e) { /* drop-silent — observability sink */ }
458
- }
443
+ var _emitMetric = observability().namespaced("middleware.tusUpload", auditOn);
459
444
 
460
445
  async function _handleOptions(req, res) {
461
446
  var headers = _emitTusBaseHeaders(res, {
@@ -29,6 +29,7 @@
29
29
  var lazyRequire = require("../lazy-require");
30
30
  var safeJson = require("../safe-json");
31
31
  var validateOpts = require("../validate-opts");
32
+ var denyResponse = require("./deny-response");
32
33
  var { defineClass } = require("../framework-error");
33
34
 
34
35
  var WebAppManifestError = defineClass("WebAppManifestError", { alwaysPermanent: true });
@@ -135,13 +136,7 @@ function create(opts) {
135
136
  (alsoAtJsonPath && path === "/manifest.json");
136
137
  if (!matches) return next();
137
138
  if (req.method !== "GET" && req.method !== "HEAD") {
138
- var bodyMsg = "Method Not Allowed";
139
- res.writeHead(405, { // HTTP 405 status
140
- "Allow": "GET, HEAD",
141
- "Content-Type": "text/plain; charset=utf-8",
142
- "Content-Length": Buffer.byteLength(bodyMsg),
143
- });
144
- res.end(bodyMsg);
139
+ denyResponse.methodNotAllowed(res, "GET, HEAD");
145
140
  return;
146
141
  }
147
142
  res.writeHead(200, { // HTTP 200 status
package/lib/migrations.js CHANGED
@@ -39,6 +39,7 @@
39
39
  */
40
40
 
41
41
  var nodePath = require("node:path");
42
+ var moduleLoader = require("./module-loader");
42
43
  var atomicFile = require("./atomic-file");
43
44
  var dbSchema = require("./db-schema");
44
45
  var frameworkSchema = require("./framework-schema");
@@ -269,21 +270,11 @@ function _resolveDb(opts) {
269
270
  }
270
271
 
271
272
  function _loadMigration(file, dir) {
272
- var fullPath = nodePath.join(dir, file);
273
- // Drop the require cache for this path before loading so a test that
274
- // changes a migration file between calls picks up the new content.
275
- // Production deployments would always restart the process, but this
276
- // keeps test fixtures sane.
277
- try { delete require.cache[require.resolve(fullPath)]; } catch (_e) { /* not yet cached */ }
278
- var mod;
279
- // Operator-supplied migration — dynamic by design, can't be bundle-
280
- // traced. Host-CLI scope; deploying via SEA / pkg drops this surface.
281
- try { mod = require(fullPath); } // allow:dynamic-require — operator-supplied migration
282
- catch (e) {
283
- throw new MigrationError("migrations/load-failed",
273
+ var mod = moduleLoader.requireFresh(nodePath.join(dir, file), function (e) {
274
+ return new MigrationError("migrations/load-failed",
284
275
  "migration '" + file + "' failed to load: " + ((e && e.message) || String(e)),
285
276
  true);
286
- }
277
+ });
287
278
  if (!mod || typeof mod.up !== "function") {
288
279
  throw new MigrationError("migrations/missing-up",
289
280
  "migration '" + file + "' must export an `up(db)` function", true);
package/lib/mime-parse.js CHANGED
@@ -37,32 +37,48 @@
37
37
  * mdn: 1 MiB) so this module's hot-path doesn't add its own cap.
38
38
  */
39
39
 
40
- function parseHeaderBlock(text) {
41
- // RFC 5322 §2.2.3continuation lines (lines starting with WSP)
42
- // fold onto the previous header value. The header section ends at
43
- // the first empty line; subsequent lines belong to the body.
44
- var lines = text.split(/\r?\n/);
45
- var unfolded = [];
40
+ function classifyHeaderBlock(text) {
41
+ // RFC 5322 §2.2 — every line of a header section is either a header field
42
+ // (`name: value`), a folding continuation (leading WSP), or the empty line
43
+ // that ends the section. Anything else is MALFORMED and a colon-less line
44
+ // sitting in the header section is the header-injection / SMTP-smuggling
45
+ // signal (attacker content on a bare line followed by an injected
46
+ // Bcc/To/From header). `fields` is the parsed headers (boundary-aware,
47
+ // continuation-unfolded); `malformed` is the injection/structure evidence the
48
+ // silent-skip parsers (email, mime, dsn, arc) all dropped on the floor.
49
+ var lines = String(text == null ? "" : text).split(/\r?\n/);
50
+ var unfolded = []; // [{ line, lineIndex }]
46
51
  for (var i = 0; i < lines.length; i += 1) {
47
52
  var line = lines[i];
48
- if (line.length === 0) break;
53
+ if (line.length === 0) break; // header/body boundary
49
54
  if ((line.charAt(0) === " " || line.charAt(0) === "\t") && unfolded.length > 0) {
50
- unfolded[unfolded.length - 1] += " " + line.replace(/^\s+/, "");
55
+ unfolded[unfolded.length - 1].line += " " + line.replace(/^\s+/, "");
51
56
  } else {
52
- unfolded.push(line);
57
+ unfolded.push({ line: line, lineIndex: i });
53
58
  }
54
59
  }
55
- var headers = [];
60
+ var fields = [];
61
+ var malformed = [];
56
62
  for (var j = 0; j < unfolded.length; j += 1) {
57
- var l = unfolded[j];
58
- var colonAt = l.indexOf(":");
59
- if (colonAt === -1) continue;
60
- headers.push({
61
- name: l.slice(0, colonAt).trim(),
62
- value: l.slice(colonAt + 1).trim(),
63
+ var entry = unfolded[j];
64
+ var colonAt = entry.line.indexOf(":");
65
+ if (colonAt === -1) {
66
+ malformed.push({ lineIndex: entry.lineIndex, line: entry.line, reason: "no-colon" });
67
+ continue;
68
+ }
69
+ fields.push({
70
+ name: entry.line.slice(0, colonAt).trim(),
71
+ value: entry.line.slice(colonAt + 1).trim(),
63
72
  });
64
73
  }
65
- return headers;
74
+ return { fields: fields, malformed: malformed };
75
+ }
76
+
77
+ function parseHeaderBlock(text) {
78
+ // The fields view of the shared classifier — kept for every caller that only
79
+ // wants the parsed headers (the malformed lines are reached via
80
+ // classifyHeaderBlock for structure/injection validation).
81
+ return classifyHeaderBlock(text).fields;
66
82
  }
67
83
 
68
84
  function splitHeadersAndBody(text) {
@@ -189,6 +205,7 @@ function addressType(addr) {
189
205
 
190
206
  module.exports = {
191
207
  parseHeaderBlock: parseHeaderBlock,
208
+ classifyHeaderBlock: classifyHeaderBlock,
192
209
  splitHeadersAndBody: splitHeadersAndBody,
193
210
  findHeader: findHeader,
194
211
  parseContentType: parseContentType,
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * lib/module-loader.js — the single audited entry point for loading an
4
+ * operator-supplied module file (a migration or a seed) by path.
5
+ *
6
+ * Operator modules execute arbitrary code on `require`, so the dynamic
7
+ * `require()` lives here behind ONE `allow:dynamic-require` marker rather
8
+ * than scattered across every host-CLI loader (`b.migrations`,
9
+ * `b.seeders`, `b.externalDb.migrate`). The require cache is busted first
10
+ * so a dev / test rewriting a fixture between calls picks up the new
11
+ * content (production deployments restart the process). The dynamic
12
+ * require does not survive SEA / esbuild bundling — operator migrations
13
+ * and seeds are host-CLI scope, not framework-internal scope.
14
+ *
15
+ * The caller owns path construction (it knows its own directory layout)
16
+ * and the typed, domain-specific error it throws on a load failure
17
+ * (parse error, throwing top-level code), so resolution stays identical
18
+ * to the per-loader form it replaces.
19
+ */
20
+
21
+ /**
22
+ * requireFresh(absPath, onLoadError) — bust the require cache for
23
+ * `absPath`, then require it fresh. `absPath` MUST be absolute (a bare
24
+ * relative path would resolve against node_modules, which is never an
25
+ * operator file). On a load failure, `onLoadError(err)` builds the
26
+ * caller's typed error, which is thrown.
27
+ *
28
+ * var mod = moduleLoader.requireFresh(path.join(dir, file), function (e) {
29
+ * return new MigrationError("migrations/load-failed",
30
+ * "migration '" + file + "' failed to load: " + ((e && e.message) || String(e)), true);
31
+ * });
32
+ */
33
+ function requireFresh(absPath, onLoadError) {
34
+ try { delete require.cache[require.resolve(absPath)]; } catch (_e) { /* not yet cached */ }
35
+ try {
36
+ return require(absPath); // allow:dynamic-require — operator-supplied module (migration / seed)
37
+ } catch (e) {
38
+ throw onLoadError(e);
39
+ }
40
+ }
41
+
42
+ module.exports = {
43
+ requireFresh: requireFresh,
44
+ };
package/lib/money.js CHANGED
@@ -277,6 +277,32 @@ Money.prototype.multiply = function (factor, opts) {
277
277
  return new Money(quotient, this.currency);
278
278
  };
279
279
 
280
+ /**
281
+ * @primitive b.money.Money.roundToIncrement
282
+ * @signature b.money.Money.roundToIncrement(step, opts?)
283
+ * @since 0.15.13
284
+ * @status stable
285
+ * @related b.money.roundMinor, b.money.Money
286
+ *
287
+ * Snap this amount to the nearest multiple of `step` minor units, returning a
288
+ * new `Money` in the same currency — the cash-rounding step a coarser
289
+ * denomination needs (CHF to the nearest 0.05, SEK to the nearest 0.10, a
290
+ * 100-unit price step) without leaving the type. Integer-only; immutable;
291
+ * negative amounts (refund previews) round on the correct side of the tie. See
292
+ * `b.money.roundMinor` for the raw-integer form and the mode semantics.
293
+ *
294
+ * @opts
295
+ * mode: "half-even" | "half-up" | "half-down" | "ceiling" | "floor", // default: half-even
296
+ *
297
+ * @example
298
+ * b.money.of("12.32", "CHF").roundToIncrement(5, { mode: "half-up" }); // → CHF 12.30
299
+ * b.money.of("19.97", "SEK").roundToIncrement(10); // → SEK 20.00
300
+ */
301
+ Money.prototype.roundToIncrement = function (step, opts) {
302
+ opts = opts || {};
303
+ return new Money(roundMinor(this._minor, step, opts.mode || "half-even"), this.currency);
304
+ };
305
+
280
306
  // _rationalFromDecimalString -- `"1.085"` -> { num: 1085n, den: 1000n }.
281
307
  // Strict shape; same refusals as _parseDecimalString.
282
308
  function _rationalFromDecimalString(s) {
@@ -333,6 +359,84 @@ function _divRound(n, d, rounding) {
333
359
  return r < 0n ? q - 1n : q + 1n;
334
360
  }
335
361
 
362
+ // Cash-rounding modes for roundMinor / Money.roundToIncrement. half-even
363
+ // (banker's) is the default and matches the rest of the module; half-up rounds
364
+ // a tie away from zero, half-down toward zero; ceiling/floor are directional
365
+ // (toward +inf / -inf) regardless of distance.
366
+ var INCREMENT_MODES = {
367
+ "half-even": true, "half-up": true, "half-down": true, "ceiling": true, "floor": true,
368
+ };
369
+
370
+ function _toIncrementBigInt(step) {
371
+ if (typeof step === "bigint") {
372
+ if (step <= 0n) throw new MoneyError("money/bad-increment",
373
+ "step must be a positive integer of minor units");
374
+ return step;
375
+ }
376
+ if (typeof step === "number" && Number.isInteger(step) && step > 0) return BigInt(step);
377
+ throw new MoneyError("money/bad-increment",
378
+ "step must be a positive integer (BigInt or safe integer Number) of minor units; got " +
379
+ (typeof step === "number" ? String(step) : typeof step));
380
+ }
381
+
382
+ /**
383
+ * @primitive b.money.roundMinor
384
+ * @signature b.money.roundMinor(minor, step, mode?)
385
+ * @since 0.15.13
386
+ * @status stable
387
+ * @related b.money.Money, b.money.fromMinorUnits
388
+ *
389
+ * Snap a raw minor-unit integer to the nearest multiple of `step` minor units —
390
+ * the cash-rounding step a coarser cash denomination needs even though the
391
+ * currency's ISO 4217 minor unit is finer (a CHF total to the nearest 5 rappen
392
+ * after the 1/2-rappen coins were retired, a SEK total to the nearest 10 öre, a
393
+ * JPY total to a 100-unit psychological-pricing step). Pure BigInt math — no
394
+ * `Number` in the value path — and the remainder sign is handled so a negative
395
+ * amount (a refund preview) rounds on the correct side of the tie.
396
+ *
397
+ * `minor` accepts a BigInt or a safe integer `Number`; the return is a BigInt.
398
+ *
399
+ * @opts
400
+ * mode: "half-even" | "half-up" | "half-down" | "ceiling" | "floor", // default: half-even
401
+ *
402
+ * @example
403
+ * b.money.roundMinor(1232n, 5n); // CHF 12.32 → nearest 0.05 → 1230n (12.30)
404
+ * b.money.roundMinor(25n, 10n, "half-even"); // tie → even multiple → 20n
405
+ * b.money.roundMinor(25n, 10n, "half-up"); // tie away from zero → 30n
406
+ * b.money.roundMinor(-25n, 10n, "half-up"); // refund tie away from zero → -30n
407
+ */
408
+ function roundMinor(minor, step, mode) {
409
+ mode = mode || "half-even";
410
+ if (typeof minor === "number" && Number.isInteger(minor)) minor = BigInt(minor);
411
+ if (typeof minor !== "bigint") {
412
+ throw new MoneyError("money/bad-minor-units",
413
+ "minor must be an integer (BigInt or safe integer Number); got " + (typeof minor));
414
+ }
415
+ if (!Object.prototype.hasOwnProperty.call(INCREMENT_MODES, mode)) {
416
+ throw new MoneyError("money/bad-rounding-mode",
417
+ "mode must be one of half-even | half-up | half-down | ceiling | floor; got " + String(mode));
418
+ }
419
+ var stepBig = _toIncrementBigInt(step);
420
+ var q = minor / stepBig;
421
+ var r = minor - q * stepBig;
422
+ if (r === 0n) return minor;
423
+ // lower = the multiple toward -inf, upper = toward +inf. BigInt division
424
+ // truncates toward zero, so the bracket flips by sign of `minor`.
425
+ var lower, upper;
426
+ if (minor >= 0n) { lower = q * stepBig; upper = lower + stepBig; }
427
+ else { upper = q * stepBig; lower = upper - stepBig; }
428
+ if (mode === "floor") return lower;
429
+ if (mode === "ceiling") return upper;
430
+ var distLow = minor - lower; // >= 0
431
+ var distHigh = upper - minor; // >= 0
432
+ if (distLow < distHigh) return lower;
433
+ if (distHigh < distLow) return upper;
434
+ // Exactly on the tie.
435
+ if (mode === "half-up") return (minor >= 0n) ? upper : lower; // away from zero
436
+ if (mode === "half-down") return (minor >= 0n) ? lower : upper; // toward zero
437
+ return ((lower / stepBig) % 2n === 0n) ? lower : upper; // half-even
438
+ }
439
+
336
440
  // allocate -- split `this` into `weights.length` parts proportional to
337
441
  // the weights, distributing every minor unit. Largest-remainder
338
442
  // method: floor each share, then hand out the leftover units to the
@@ -693,6 +797,7 @@ module.exports = {
693
797
  parse: parse,
694
798
  zero: zero,
695
799
  convert: convert,
800
+ roundMinor: roundMinor,
696
801
  CURRENCIES: CURRENCIES,
697
802
  Money: Money,
698
803
  MoneyError: MoneyError,