@blamejs/blamejs-shop 0.4.68 → 0.4.70

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 (298) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/admin.js +8 -6
  3. package/lib/asset-manifest.json +1 -1
  4. package/lib/giftcards.js +29 -5
  5. package/lib/security-middleware.js +65 -23
  6. package/lib/storefront.js +10 -7
  7. package/lib/vendor/MANIFEST.json +319 -267
  8. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  9. package/lib/vendor/blamejs/api-snapshot.json +58 -5
  10. package/lib/vendor/blamejs/examples/wiki/README.md +1 -1
  11. package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +9 -8
  12. package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +10 -9
  13. package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +4 -3
  14. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +33 -17
  15. package/lib/vendor/blamejs/examples/wiki/routes/admin.js +7 -10
  16. package/lib/vendor/blamejs/examples/wiki/server.js +5 -4
  17. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +5 -0
  18. package/lib/vendor/blamejs/lib/a2a-tasks.js +38 -6
  19. package/lib/vendor/blamejs/lib/agent-event-bus.js +13 -0
  20. package/lib/vendor/blamejs/lib/agent-idempotency.js +5 -1
  21. package/lib/vendor/blamejs/lib/agent-snapshot.js +32 -2
  22. package/lib/vendor/blamejs/lib/ai-aedt-bias-audit.js +2 -1
  23. package/lib/vendor/blamejs/lib/ai-content-detect.js +1 -3
  24. package/lib/vendor/blamejs/lib/ai-frontier-protocol.js +1 -1
  25. package/lib/vendor/blamejs/lib/ai-model-manifest.js +1 -1
  26. package/lib/vendor/blamejs/lib/ai-output.js +16 -7
  27. package/lib/vendor/blamejs/lib/api-snapshot.js +4 -1
  28. package/lib/vendor/blamejs/lib/app-shutdown.js +7 -1
  29. package/lib/vendor/blamejs/lib/archive-gz.js +9 -0
  30. package/lib/vendor/blamejs/lib/archive-read.js +9 -7
  31. package/lib/vendor/blamejs/lib/archive-tar-read.js +51 -8
  32. package/lib/vendor/blamejs/lib/archive.js +4 -2
  33. package/lib/vendor/blamejs/lib/asn1-der.js +70 -22
  34. package/lib/vendor/blamejs/lib/atomic-file.js +204 -2
  35. package/lib/vendor/blamejs/lib/audit-chain.js +54 -5
  36. package/lib/vendor/blamejs/lib/audit-daily-review.js +12 -2
  37. package/lib/vendor/blamejs/lib/audit-sign.js +2 -1
  38. package/lib/vendor/blamejs/lib/audit-tools.js +108 -23
  39. package/lib/vendor/blamejs/lib/audit.js +7 -2
  40. package/lib/vendor/blamejs/lib/auth/access-lock.js +2 -2
  41. package/lib/vendor/blamejs/lib/auth/bot-challenge.js +1 -1
  42. package/lib/vendor/blamejs/lib/auth/ciba.js +43 -4
  43. package/lib/vendor/blamejs/lib/auth/dpop.js +6 -1
  44. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +5 -1
  45. package/lib/vendor/blamejs/lib/auth/jwt.js +2 -2
  46. package/lib/vendor/blamejs/lib/auth/lockout.js +18 -2
  47. package/lib/vendor/blamejs/lib/auth/passkey.js +1 -1
  48. package/lib/vendor/blamejs/lib/auth/password.js +1 -1
  49. package/lib/vendor/blamejs/lib/auth/saml.js +33 -13
  50. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +24 -4
  51. package/lib/vendor/blamejs/lib/auth/status-list.js +14 -2
  52. package/lib/vendor/blamejs/lib/auth/step-up.js +9 -1
  53. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +21 -2
  54. package/lib/vendor/blamejs/lib/backup/bundle.js +7 -2
  55. package/lib/vendor/blamejs/lib/backup/crypto.js +23 -8
  56. package/lib/vendor/blamejs/lib/backup/index.js +41 -20
  57. package/lib/vendor/blamejs/lib/backup/manifest.js +7 -1
  58. package/lib/vendor/blamejs/lib/break-glass.js +41 -22
  59. package/lib/vendor/blamejs/lib/cbor.js +34 -11
  60. package/lib/vendor/blamejs/lib/cdn-cache-control.js +7 -3
  61. package/lib/vendor/blamejs/lib/cert.js +5 -3
  62. package/lib/vendor/blamejs/lib/cli.js +5 -1
  63. package/lib/vendor/blamejs/lib/cloud-events.js +3 -2
  64. package/lib/vendor/blamejs/lib/cluster-storage.js +7 -3
  65. package/lib/vendor/blamejs/lib/codepoint-class.js +17 -0
  66. package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -1
  67. package/lib/vendor/blamejs/lib/compliance-sanctions.js +9 -7
  68. package/lib/vendor/blamejs/lib/compliance.js +1 -1
  69. package/lib/vendor/blamejs/lib/config-drift.js +22 -8
  70. package/lib/vendor/blamejs/lib/content-credentials.js +11 -8
  71. package/lib/vendor/blamejs/lib/content-digest.js +11 -4
  72. package/lib/vendor/blamejs/lib/cookies.js +10 -2
  73. package/lib/vendor/blamejs/lib/cose.js +20 -0
  74. package/lib/vendor/blamejs/lib/crdt.js +2 -1
  75. package/lib/vendor/blamejs/lib/crypto-field.js +29 -23
  76. package/lib/vendor/blamejs/lib/crypto.js +18 -4
  77. package/lib/vendor/blamejs/lib/csp.js +4 -0
  78. package/lib/vendor/blamejs/lib/daemon.js +4 -1
  79. package/lib/vendor/blamejs/lib/data-act.js +27 -4
  80. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +14 -6
  81. package/lib/vendor/blamejs/lib/db-query.js +69 -9
  82. package/lib/vendor/blamejs/lib/db.js +32 -15
  83. package/lib/vendor/blamejs/lib/dora.js +43 -13
  84. package/lib/vendor/blamejs/lib/dr-runbook.js +1 -1
  85. package/lib/vendor/blamejs/lib/dsa.js +2 -1
  86. package/lib/vendor/blamejs/lib/dsr.js +22 -8
  87. package/lib/vendor/blamejs/lib/early-hints.js +19 -0
  88. package/lib/vendor/blamejs/lib/eat.js +5 -1
  89. package/lib/vendor/blamejs/lib/external-db.js +60 -4
  90. package/lib/vendor/blamejs/lib/fda-21cfr11.js +30 -5
  91. package/lib/vendor/blamejs/lib/flag-providers.js +6 -2
  92. package/lib/vendor/blamejs/lib/forms.js +1 -1
  93. package/lib/vendor/blamejs/lib/gate-contract.js +46 -5
  94. package/lib/vendor/blamejs/lib/gdpr-ropa.js +18 -9
  95. package/lib/vendor/blamejs/lib/graphql-federation.js +17 -4
  96. package/lib/vendor/blamejs/lib/guard-all.js +2 -2
  97. package/lib/vendor/blamejs/lib/guard-dsn.js +1 -1
  98. package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
  99. package/lib/vendor/blamejs/lib/guard-html.js +9 -11
  100. package/lib/vendor/blamejs/lib/guard-imap-command.js +1 -1
  101. package/lib/vendor/blamejs/lib/guard-jmap.js +1 -1
  102. package/lib/vendor/blamejs/lib/guard-json.js +14 -6
  103. package/lib/vendor/blamejs/lib/guard-mail-move.js +1 -1
  104. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +1 -1
  105. package/lib/vendor/blamejs/lib/guard-pop3-command.js +1 -1
  106. package/lib/vendor/blamejs/lib/guard-smtp-command.js +1 -1
  107. package/lib/vendor/blamejs/lib/guard-svg.js +8 -9
  108. package/lib/vendor/blamejs/lib/html-balance.js +7 -3
  109. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +33 -12
  110. package/lib/vendor/blamejs/lib/http-client.js +225 -53
  111. package/lib/vendor/blamejs/lib/iab-tcf.js +3 -2
  112. package/lib/vendor/blamejs/lib/importmap-integrity.js +41 -1
  113. package/lib/vendor/blamejs/lib/incident-report.js +9 -6
  114. package/lib/vendor/blamejs/lib/json-patch.js +1 -1
  115. package/lib/vendor/blamejs/lib/json-path.js +24 -3
  116. package/lib/vendor/blamejs/lib/jtd.js +2 -2
  117. package/lib/vendor/blamejs/lib/legal-hold.js +24 -8
  118. package/lib/vendor/blamejs/lib/log.js +2 -2
  119. package/lib/vendor/blamejs/lib/mail-agent.js +2 -2
  120. package/lib/vendor/blamejs/lib/mail-arf.js +1 -1
  121. package/lib/vendor/blamejs/lib/mail-auth.js +3 -3
  122. package/lib/vendor/blamejs/lib/mail-bimi.js +16 -16
  123. package/lib/vendor/blamejs/lib/mail-bounce.js +3 -3
  124. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +71 -6
  125. package/lib/vendor/blamejs/lib/mail-deploy.js +9 -5
  126. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -4
  127. package/lib/vendor/blamejs/lib/mail-helo.js +2 -4
  128. package/lib/vendor/blamejs/lib/mail-journal.js +11 -8
  129. package/lib/vendor/blamejs/lib/mail-mdn.js +8 -4
  130. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -4
  131. package/lib/vendor/blamejs/lib/mail-scan.js +3 -5
  132. package/lib/vendor/blamejs/lib/mail-server-jmap.js +4 -1
  133. package/lib/vendor/blamejs/lib/mail-server-registry.js +1 -1
  134. package/lib/vendor/blamejs/lib/mail-server-tls.js +9 -2
  135. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -4
  136. package/lib/vendor/blamejs/lib/mail-store-fts.js +1 -1
  137. package/lib/vendor/blamejs/lib/mail.js +22 -2
  138. package/lib/vendor/blamejs/lib/markup-tokenizer.js +24 -0
  139. package/lib/vendor/blamejs/lib/mcp.js +6 -4
  140. package/lib/vendor/blamejs/lib/mdoc.js +26 -3
  141. package/lib/vendor/blamejs/lib/metrics.js +14 -3
  142. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +2 -2
  143. package/lib/vendor/blamejs/lib/middleware/body-parser.js +10 -4
  144. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +26 -18
  145. package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +5 -1
  146. package/lib/vendor/blamejs/lib/middleware/compression.js +9 -0
  147. package/lib/vendor/blamejs/lib/middleware/cors.js +32 -23
  148. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +60 -21
  149. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -4
  150. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +28 -4
  151. package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +61 -30
  152. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +25 -16
  153. package/lib/vendor/blamejs/lib/middleware/scim-server.js +2 -1
  154. package/lib/vendor/blamejs/lib/middleware/security-headers.js +24 -6
  155. package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +6 -3
  156. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +2 -2
  157. package/lib/vendor/blamejs/lib/money.js +1 -1
  158. package/lib/vendor/blamejs/lib/mtls-ca.js +10 -6
  159. package/lib/vendor/blamejs/lib/network-dns-resolver.js +1 -1
  160. package/lib/vendor/blamejs/lib/network-dns.js +9 -2
  161. package/lib/vendor/blamejs/lib/network-dnssec.js +2 -1
  162. package/lib/vendor/blamejs/lib/network-smtp-policy.js +23 -5
  163. package/lib/vendor/blamejs/lib/network-tls.js +27 -5
  164. package/lib/vendor/blamejs/lib/network-tsig.js +2 -2
  165. package/lib/vendor/blamejs/lib/nis2-report.js +1 -1
  166. package/lib/vendor/blamejs/lib/nist-crosswalk.js +1 -1
  167. package/lib/vendor/blamejs/lib/ntp-check.js +28 -0
  168. package/lib/vendor/blamejs/lib/numeric-bounds.js +9 -0
  169. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +1 -2
  170. package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +4 -2
  171. package/lib/vendor/blamejs/lib/object-store/gcs.js +6 -4
  172. package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -2
  173. package/lib/vendor/blamejs/lib/object-store/http-request.js +30 -1
  174. package/lib/vendor/blamejs/lib/object-store/local.js +37 -17
  175. package/lib/vendor/blamejs/lib/object-store/sigv4.js +1 -2
  176. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +20 -4
  177. package/lib/vendor/blamejs/lib/outbox.js +11 -4
  178. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +1 -1
  179. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +21 -3
  180. package/lib/vendor/blamejs/lib/queue-local.js +10 -3
  181. package/lib/vendor/blamejs/lib/redact.js +7 -3
  182. package/lib/vendor/blamejs/lib/request-helpers.js +201 -23
  183. package/lib/vendor/blamejs/lib/resource-access-lock.js +3 -3
  184. package/lib/vendor/blamejs/lib/restore-bundle.js +46 -18
  185. package/lib/vendor/blamejs/lib/restore-rollback.js +10 -4
  186. package/lib/vendor/blamejs/lib/restore.js +19 -0
  187. package/lib/vendor/blamejs/lib/retention.js +20 -4
  188. package/lib/vendor/blamejs/lib/router.js +17 -4
  189. package/lib/vendor/blamejs/lib/safe-ical.js +2 -2
  190. package/lib/vendor/blamejs/lib/safe-icap.js +1 -1
  191. package/lib/vendor/blamejs/lib/safe-json.js +44 -0
  192. package/lib/vendor/blamejs/lib/safe-sieve.js +1 -1
  193. package/lib/vendor/blamejs/lib/safe-vcard.js +1 -1
  194. package/lib/vendor/blamejs/lib/sandbox-worker.js +6 -0
  195. package/lib/vendor/blamejs/lib/sandbox.js +1 -1
  196. package/lib/vendor/blamejs/lib/scheduler.js +17 -1
  197. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +16 -0
  198. package/lib/vendor/blamejs/lib/session.js +27 -3
  199. package/lib/vendor/blamejs/lib/sql.js +3 -3
  200. package/lib/vendor/blamejs/lib/static.js +65 -13
  201. package/lib/vendor/blamejs/lib/template.js +7 -5
  202. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -19
  203. package/lib/vendor/blamejs/lib/tsa.js +5 -2
  204. package/lib/vendor/blamejs/lib/vault/index.js +5 -0
  205. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +22 -26
  206. package/lib/vendor/blamejs/lib/vault/passphrase-source.js +8 -3
  207. package/lib/vendor/blamejs/lib/vault/rotate.js +13 -18
  208. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +4 -1
  209. package/lib/vendor/blamejs/lib/vc.js +1 -1
  210. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +10 -10
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +23 -10
  212. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5498 -5494
  213. package/lib/vendor/blamejs/lib/webhook.js +16 -1
  214. package/lib/vendor/blamejs/lib/websocket.js +1 -1
  215. package/lib/vendor/blamejs/lib/worm.js +1 -1
  216. package/lib/vendor/blamejs/lib/ws-client.js +57 -46
  217. package/lib/vendor/blamejs/lib/x509-chain.js +44 -0
  218. package/lib/vendor/blamejs/package.json +1 -1
  219. package/lib/vendor/blamejs/release-notes/v0.15.14.json +122 -0
  220. package/lib/vendor/blamejs/scripts/check-vendor-currency.js +119 -4
  221. package/lib/vendor/blamejs/test/00-primitives.js +5 -1
  222. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +18 -4
  223. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +42 -0
  224. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +36 -0
  225. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  226. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +47 -0
  227. package/lib/vendor/blamejs/test/layer-0-primitives/archive-gz.test.js +24 -0
  228. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-hardening.test.js +160 -0
  229. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +45 -0
  230. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +30 -0
  231. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-open-nofollow.test.js +79 -0
  232. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-excl.test.js +132 -0
  233. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-write-stream.test.js +181 -0
  234. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-corrupted-anchor.test.js +65 -0
  235. package/lib/vendor/blamejs/test/layer-0-primitives/audit-chain-incremental-verify.test.js +83 -0
  236. package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +48 -1
  237. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +13 -3
  238. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +122 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +37 -0
  240. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +5 -3
  241. package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +21 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +73 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +17 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +62 -3
  245. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +12 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-storage.test.js +40 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +146 -5
  248. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +14 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/compression-range.test.js +115 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +17 -5
  251. package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +27 -5
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +83 -0
  253. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +58 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +30 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +74 -0
  256. package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +20 -6
  257. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-alg-kty.test.js +64 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +32 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +43 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +30 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +33 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +34 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +12 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +72 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-throttle-transform.test.js +88 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +25 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +28 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +20 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/mail-header-injection.test.js +58 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +63 -9
  271. package/lib/vendor/blamejs/test/layer-0-primitives/mdoc.test.js +41 -14
  272. package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +61 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/object-store-range-header.test.js +51 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +35 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/output-header-hardening.test.js +102 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/parser-verify-hardening.test.js +191 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/proto-shadow-allowlist.test.js +120 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +75 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +128 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/restore-blob-remap.test.js +128 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/retention-sweep-termination.test.js +104 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/router-body-validation.test.js +98 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json-stringify-for-script.test.js +43 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +48 -5
  285. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +23 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +54 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +24 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +42 -1
  289. package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +7 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/template-escape-html.test.js +43 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +15 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/vault-default-store.test.js +48 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/vendor-currency-classify.test.js +77 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +50 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +22 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/x509-chain-ca-enforcement.test.js +149 -0
  297. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +34 -0
  298. package/package.json +1 -1
@@ -716,6 +716,9 @@ function _stripCrossOriginAuth(headers) {
716
716
  * responseMode: "buffer", // "buffer" | "stream" | "always-resolve"
717
717
  * maxResponseBytes: undefined, // 16 MiB control / 1 GiB GET defaults; ignored in "stream"
718
718
  * onChunk: undefined, // (chunk: Buffer) => void — fires per response chunk
719
+ * maxBytesPerSec: undefined, // token-bucket bandwidth cap (bytes/sec) — paces BOTH the download response and the upload body with backpressure
720
+ * downloadTransform: undefined, // Transform | () => Transform | array — interpose on the response stream (e.g. a hashing or progress Transform)
721
+ * uploadTransform: undefined, // Transform | () => Transform | array — interpose on the request body before the wire
719
722
  * signal: undefined, // AbortSignal — propagated to req / stream
720
723
  * errorClass: HttpClientError, // FrameworkError subclass for thrown errors
721
724
  * observer: undefined, // (stage, info) => void — lifecycle hook
@@ -733,6 +736,132 @@ function _stripCrossOriginAuth(headers) {
733
736
  * });
734
737
  * // → { statusCode: 200, headers: { "content-type": "application/json", ... }, body: <Buffer> }
735
738
  */
739
+ // Token-bucket bandwidth throttle as a Transform. Splits each chunk to the
740
+ // credit available, releasing at most `bytesPerSec` per second (1s burst
741
+ // capacity). Because `_transform`'s callback is not called until the whole
742
+ // chunk has been released, backpressure propagates upstream — on a download
743
+ // the socket pauses, on an upload the body source pauses. Wired into both the
744
+ // response (download) and request-body (upload) pipelines so the helpers'
745
+ // SSRF guard / DNS pinning / byte caps / atomic-rename are preserved.
746
+ function _throttleStream(bytesPerSec) {
747
+ var capacity = bytesPerSec; // allow at most 1s worth of burst
748
+ var tokens = capacity;
749
+ var last = Date.now();
750
+ function refill() {
751
+ var now = Date.now();
752
+ if (now > last) {
753
+ tokens = Math.min(capacity, tokens + ((now - last) / 1000) * bytesPerSec);
754
+ last = now;
755
+ }
756
+ }
757
+ return new nodeStream.Transform({
758
+ transform: function (chunk, _enc, cb) {
759
+ var self = this;
760
+ var offset = 0;
761
+ function pump() {
762
+ refill();
763
+ if (offset >= chunk.length) { cb(); return; }
764
+ var avail = Math.floor(tokens);
765
+ if (avail >= 1) {
766
+ var n = Math.min(chunk.length - offset, avail);
767
+ tokens -= n;
768
+ self.push(chunk.subarray(offset, offset + n));
769
+ offset += n;
770
+ if (offset >= chunk.length) { cb(); return; }
771
+ setImmediate(pump); // more bytes, maybe more credit already
772
+ } else {
773
+ // ms to accrue one more byte of credit = (deficit / rate) seconds.
774
+ var waitMs = Math.ceil(C.TIME.seconds((1 - tokens) / bytesPerSec)) + 1;
775
+ var t = setTimeout(pump, waitMs);
776
+ if (t && typeof t.unref === "function") t.unref();
777
+ }
778
+ }
779
+ pump();
780
+ },
781
+ });
782
+ }
783
+
784
+ // Validate + normalize a transform opt into an array. Each entry may be a
785
+ // Transform stream instance OR a `() => Transform` factory (the factory form is
786
+ // retry/redirect-safe — a single Transform instance can only be piped once, so
787
+ // a fresh one is built per attempt). Returns { ok: [...] } or { err: Error }.
788
+ function _coerceTransforms(value, errorClass, name) {
789
+ if (value === undefined || value === null) return { ok: [] };
790
+ var list = Array.isArray(value) ? value : [value];
791
+ for (var i = 0; i < list.length; i++) {
792
+ var t = list[i];
793
+ var isFactory = typeof t === "function";
794
+ var isTransform = t && typeof t.pipe === "function" && typeof t.write === "function";
795
+ if (!isFactory && !isTransform) {
796
+ return { err: _makeError(errorClass, "BAD_ARG",
797
+ name + " must be a Transform stream or a () => Transform factory (or an array of them)", true) };
798
+ }
799
+ }
800
+ return { ok: list };
801
+ }
802
+
803
+ // Resolve a transform entry to a fresh stream instance (call the factory form).
804
+ function _resolveStage(t) { return typeof t === "function" ? t() : t; }
805
+
806
+ // Compose the response (download) stream: source → [throttle?] → [transforms…]
807
+ // → observe(progress + onChunk). Every stage is a Transform so backpressure
808
+ // flows from the consumer back to the socket (the throttle paces it). Returns
809
+ // `source` unchanged when nothing is interposed (preserves the bare-stream
810
+ // contract). A stage error propagates downstream so the returned body emits it.
811
+ function _buildDownloadStream(source, emitDownload, onChunk, throttleBps, transforms) {
812
+ var stages = [];
813
+ if (throttleBps) stages.push(_throttleStream(throttleBps));
814
+ for (var i = 0; i < transforms.length; i++) stages.push(_resolveStage(transforms[i]));
815
+ if (stages.length === 0 && !emitDownload && !onChunk) return source;
816
+ var observe = new nodeStream.Transform({
817
+ transform: function (chunk, _enc, cb) {
818
+ if (emitDownload) emitDownload(chunk.length);
819
+ if (onChunk) { try { onChunk(chunk); } catch (_e) { /* operator hook — drop-silent */ } }
820
+ cb(null, chunk);
821
+ },
822
+ });
823
+ var chain = [source].concat(stages).concat([observe]);
824
+ for (var c = 0; c < chain.length - 1; c++) {
825
+ var src = chain[c], dst = chain[c + 1];
826
+ src.on("error", (function (d) { return function (e) { d.destroy(e); }; })(dst));
827
+ src.pipe(dst);
828
+ }
829
+ return observe;
830
+ }
831
+
832
+ // Build the upload throttle/transform stages (parallel to the download side).
833
+ function _uploadStages(throttleBps, transforms) {
834
+ var stages = [];
835
+ if (throttleBps) stages.push(_throttleStream(throttleBps));
836
+ for (var i = 0; i < transforms.length; i++) stages.push(_resolveStage(transforms[i]));
837
+ return stages;
838
+ }
839
+
840
+ // Pipe a body (stream | Buffer | string) through throttle/transform stages into
841
+ // the request sink, pacing the upload and emitting progress on bytes delivered
842
+ // to the sink. Used only when a throttle/transform is configured; the plain
843
+ // no-stages path keeps its original direct write. A stage/source error tears
844
+ // down the request via onBodyError.
845
+ function _pipeThrottledUpload(body, sink, stages, emitUpload, onBodyError) {
846
+ var source = (body && typeof body.pipe === "function")
847
+ ? body
848
+ : nodeStream.Readable.from(Buffer.isBuffer(body) ? body : Buffer.from(String(body), "utf8"));
849
+ var observe = new nodeStream.Transform({
850
+ transform: function (chunk, _enc, cb) {
851
+ if (emitUpload) emitUpload(chunk.length);
852
+ cb(null, chunk);
853
+ },
854
+ });
855
+ var chain = [source].concat(stages).concat([observe]);
856
+ for (var c = 0; c < chain.length - 1; c++) {
857
+ var s = chain[c], d = chain[c + 1];
858
+ s.on("error", (function (dd) { return function (e) { dd.destroy(e); }; })(d));
859
+ s.pipe(d);
860
+ }
861
+ observe.on("error", onBodyError);
862
+ observe.pipe(sink);
863
+ }
864
+
736
865
  function request(opts) {
737
866
  if (!opts || !opts.url) {
738
867
  return Promise.reject(_makeError(opts && opts.errorClass, "BAD_ARG", "url is required", true));
@@ -765,6 +894,20 @@ function request(opts) {
765
894
  return Promise.reject(_makeError(opts.errorClass, "BAD_ARG",
766
895
  "onChunk must be a function (chunk: Buffer) -> void", true));
767
896
  }
897
+ // Bandwidth cap + transform interpose (download response + upload request
898
+ // body) — validated here, derived per-attempt in _requestSingle. maxBytesPerSec
899
+ // paces BOTH legs; downloadTransform / uploadTransform interpose custom
900
+ // Transform(s) (instance or () => Transform factory) on the respective leg.
901
+ if (opts.maxBytesPerSec !== undefined && opts.maxBytesPerSec !== null) {
902
+ if (typeof opts.maxBytesPerSec !== "number" || !isFinite(opts.maxBytesPerSec) || opts.maxBytesPerSec <= 0) {
903
+ return Promise.reject(_makeError(opts.errorClass, "BAD_ARG",
904
+ "maxBytesPerSec must be a positive finite number (bytes/sec)", true));
905
+ }
906
+ }
907
+ var _dlChk = _coerceTransforms(opts.downloadTransform, opts.errorClass, "downloadTransform");
908
+ if (_dlChk.err) return Promise.reject(_dlChk.err);
909
+ var _ulChk = _coerceTransforms(opts.uploadTransform, opts.errorClass, "uploadTransform");
910
+ if (_ulChk.err) return Promise.reject(_ulChk.err);
768
911
  if (opts.jar !== undefined && opts.jar !== null) {
769
912
  if (typeof opts.jar !== "object" ||
770
913
  typeof opts.jar.cookieHeaderFor !== "function" ||
@@ -1379,6 +1522,12 @@ function _requestSingle(opts) {
1379
1522
  // ---- _requestH1: existing node:http(s) path ----
1380
1523
 
1381
1524
  function _requestH1(transport, u, opts) {
1525
+ // Bandwidth/transform interpose — opts validated in request(); derived fresh
1526
+ // per attempt (each builds its own throttle + resolves transform factories, so
1527
+ // a retry / redirect never reuses a consumed Transform).
1528
+ var throttleBps = opts.maxBytesPerSec || null; // validated in request(); positive number or absent
1529
+ var downloadTransforms = _coerceTransforms(opts.downloadTransform, opts.errorClass, "downloadTransform").ok;
1530
+ var uploadTransforms = _coerceTransforms(opts.uploadTransform, opts.errorClass, "uploadTransform").ok;
1382
1531
  return new Promise(function (resolve, reject) {
1383
1532
  var method = (opts.method || "GET").toUpperCase();
1384
1533
  var headers = Object.assign({}, opts.headers || {});
@@ -1397,7 +1546,12 @@ function _requestH1(transport, u, opts) {
1397
1546
  return;
1398
1547
  }
1399
1548
 
1400
- if (Buffer.isBuffer(opts.body)) {
1549
+ if (Buffer.isBuffer(opts.body) && uploadTransforms.length === 0) {
1550
+ // A size-changing uploadTransform (gzip / encrypt / frame) makes the
1551
+ // original buffer length wrong, so the server would truncate extra bytes
1552
+ // or wait for bytes that never arrive. Omit Content-Length in that case
1553
+ // and let the body be chunked, framed on the actual transformed bytes. A
1554
+ // throttle alone preserves size, so Content-Length stays valid then.
1401
1555
  headers["Content-Length"] = opts.body.length;
1402
1556
  }
1403
1557
  // CVE-2026-22036 mitigation — refuse compressed responses by
@@ -1465,35 +1619,30 @@ function _requestH1(transport, u, opts) {
1465
1619
  _rejectStreamHttpError(res, opts.errorClass, res.statusCode, res.statusMessage || "", _reject);
1466
1620
  return;
1467
1621
  }
1468
- if (onDownloadProgress || onChunk) {
1469
- // Wrap the stream so chunks emit progress + onChunk to the
1470
- // operator. The framework's contract is to hand back the
1471
- // response stream unmodified; fix-up via a passthrough keeps
1472
- // that contract while observing the chunk sizes. onChunk
1473
- // gets the buffer itself (for hash-as-you-go); a throw from
1474
- // it is caught and dropped so a hash-mismatch detector can
1475
- // raise without breaking the response stream caller
1476
- // surfaces the error through their own pipe handler.
1477
- var passthrough = new nodeStream.PassThrough();
1478
- res.on("data", function (chunk) {
1479
- _emitDownload(chunk.length);
1480
- if (onChunk) {
1481
- try { onChunk(chunk); }
1482
- catch (_e) { /* operator-supplied hook — drop-silent */ }
1483
- }
1484
- passthrough.write(chunk);
1485
- });
1486
- res.on("end", function () { passthrough.end(); });
1487
- res.on("error", function (e) { passthrough.destroy(e); });
1488
- return _resolve({ statusCode: res.statusCode, headers: res.headers, body: passthrough });
1489
- }
1490
- return _resolve({ statusCode: res.statusCode, headers: res.headers, body: res });
1622
+ // Compose the response stream with the optional bandwidth throttle +
1623
+ // custom transforms + progress/onChunk observation. Each is a Transform
1624
+ // so backpressure reaches the socket; onChunk sees the bytes in order
1625
+ // (for hash-as-you-go) and a throw from it is dropped. Returns `res`
1626
+ // unchanged when nothing is interposed (bare-stream contract).
1627
+ var body = _buildDownloadStream(
1628
+ res, onDownloadProgress ? _emitDownload : null, onChunk, throttleBps, downloadTransforms);
1629
+ return _resolve({ statusCode: res.statusCode, headers: res.headers, body: body });
1491
1630
  }
1492
1631
 
1493
1632
  var collector = safeBuffer.boundedChunkCollector({ maxBytes: maxResponseBytes });
1494
1633
  var capExceeded = false;
1495
1634
 
1496
- res.on("data", function (chunk) {
1635
+ // Route the buffered read through the SAME throttle + transform pipeline
1636
+ // as stream mode, so maxBytesPerSec and downloadTransform apply in buffer
1637
+ // and always-resolve modes too (both documented to pace / transform the
1638
+ // download regardless of how the body is consumed). With nothing
1639
+ // interposed this returns `res` unchanged, so the plain path is identical.
1640
+ // The cap now bounds post-transform bytes — strictly safer for a
1641
+ // decompressing transform. Progress + onChunk fire inside the pipeline.
1642
+ var dlSource = _buildDownloadStream(
1643
+ res, onDownloadProgress ? _emitDownload : null, onChunk, throttleBps, downloadTransforms);
1644
+
1645
+ dlSource.on("data", function (chunk) {
1497
1646
  if (capExceeded) return;
1498
1647
  try { collector.push(chunk); }
1499
1648
  catch (_e) {
@@ -1503,13 +1652,8 @@ function _requestH1(transport, u, opts) {
1503
1652
  "response body exceeds " + maxResponseBytes + " bytes", true));
1504
1653
  return;
1505
1654
  }
1506
- _emitDownload(chunk.length);
1507
- if (onChunk) {
1508
- try { onChunk(chunk); }
1509
- catch (_e) { /* operator-supplied hook — drop-silent */ }
1510
- }
1511
1655
  });
1512
- res.on("end", function () {
1656
+ dlSource.on("end", function () {
1513
1657
  if (capExceeded) return;
1514
1658
  var buf = collector.result();
1515
1659
  if (observer) observer("response:end", {
@@ -1539,7 +1683,7 @@ function _requestH1(transport, u, opts) {
1539
1683
  _isPermanentStatus(res.statusCode), res.statusCode));
1540
1684
  }
1541
1685
  });
1542
- res.on("error", function (e) {
1686
+ dlSource.on("error", function (e) {
1543
1687
  if (capExceeded) return;
1544
1688
  if (observer) observer("error", { phase: "response", message: e.message });
1545
1689
  _reject(_makeError(opts.errorClass, e.code || "RES_ERROR", e.message, false));
@@ -1583,7 +1727,17 @@ function _requestH1(transport, u, opts) {
1583
1727
  catch (_e) { /* progress hooks are best-effort */ }
1584
1728
  }
1585
1729
 
1586
- if (opts.body && typeof opts.body.pipe === "function") {
1730
+ var ulStages = _uploadStages(throttleBps, uploadTransforms);
1731
+ if (opts.body != null && opts.body !== "" && ulStages.length > 0) {
1732
+ // Pace / transform the upload body through the stages, into req.
1733
+ _pipeThrottledUpload(opts.body, req, ulStages,
1734
+ onUploadProgress ? _emitUpload : null,
1735
+ function (e) {
1736
+ try { req.destroy(); } catch (_) { /* best-effort req teardown */ }
1737
+ _reject(_makeError(opts.errorClass, "REQ_BODY_ERROR",
1738
+ "request body stream error: " + e.message, false));
1739
+ });
1740
+ } else if (opts.body && typeof opts.body.pipe === "function") {
1587
1741
  if (onUploadProgress) {
1588
1742
  opts.body.on("data", function (c) { _emitUpload(c.length); });
1589
1743
  }
@@ -1618,6 +1772,10 @@ function _requestH1(transport, u, opts) {
1618
1772
  // ---- _requestH2: node:http2 path ----
1619
1773
 
1620
1774
  function _requestH2(transport, u, opts) {
1775
+ // Bandwidth/transform interpose — see _requestH1; derived fresh per attempt.
1776
+ var throttleBps = opts.maxBytesPerSec || null; // validated in request(); positive number or absent
1777
+ var downloadTransforms = _coerceTransforms(opts.downloadTransform, opts.errorClass, "downloadTransform").ok;
1778
+ var uploadTransforms = _coerceTransforms(opts.uploadTransform, opts.errorClass, "uploadTransform").ok;
1621
1779
  return new Promise(function (resolve, reject) {
1622
1780
  var method = (opts.method || "GET").toUpperCase();
1623
1781
  var responseMode = opts.responseMode || "buffer";
@@ -1637,7 +1795,13 @@ function _requestH2(transport, u, opts) {
1637
1795
  }
1638
1796
 
1639
1797
  var headers = _toH2Headers(method, u, opts.headers || {});
1640
- if (Buffer.isBuffer(opts.body)) headers["content-length"] = String(opts.body.length);
1798
+ // Omit content-length when a size-changing uploadTransform is interposed —
1799
+ // the original buffer length no longer frames the transformed body (HTTP/2
1800
+ // frames via DATA + END_STREAM, so no header is required). A throttle alone
1801
+ // keeps the size, so the length stays valid then.
1802
+ if (Buffer.isBuffer(opts.body) && uploadTransforms.length === 0) {
1803
+ headers["content-length"] = String(opts.body.length);
1804
+ }
1641
1805
 
1642
1806
  if (observer) observer("request:start", { method: method, url: String(opts.url), protocol: "h2" });
1643
1807
 
@@ -1681,24 +1845,29 @@ function _requestH2(transport, u, opts) {
1681
1845
  _rejectStreamHttpError(stream, opts.errorClass, statusCode, "", _reject);
1682
1846
  return;
1683
1847
  }
1684
- if (onChunkH2) {
1685
- var passthroughH2 = new nodeStream.PassThrough();
1686
- stream.on("data", function (chunk) {
1687
- try { onChunkH2(chunk); }
1688
- catch (_e) { /* operator-supplied hook — drop-silent */ }
1689
- passthroughH2.write(chunk);
1690
- });
1691
- stream.on("end", function () { passthroughH2.end(); });
1692
- stream.on("error", function (e) { passthroughH2.destroy(e); });
1693
- return _resolve({ statusCode: statusCode, headers: responseHeaders, body: passthroughH2 });
1694
- }
1695
- return _resolve({ statusCode: statusCode, headers: responseHeaders, body: stream });
1848
+ var bodyH2 = _buildDownloadStream(stream, null, onChunkH2, throttleBps, downloadTransforms);
1849
+ return _resolve({ statusCode: statusCode, headers: responseHeaders, body: bodyH2 });
1696
1850
  }
1697
1851
 
1698
1852
  var collector = safeBuffer.boundedChunkCollector({ maxBytes: maxResponseBytes });
1699
1853
  var capExceeded = false;
1700
1854
 
1701
- stream.on("data", function (chunk) {
1855
+ // Apply the throttle + transform pipeline in buffer / always-resolve mode
1856
+ // too (matches H1 + the documented contract); returns `stream` unchanged
1857
+ // when nothing is interposed. onChunk fires inside the pipeline.
1858
+ var dlH2 = _buildDownloadStream(stream, null, onChunkH2, throttleBps, downloadTransforms);
1859
+ // When a stage is interposed, a transform error surfaces on the pipeline
1860
+ // tail, not the raw h2 stream — reject on it. The plain path (dlH2 ===
1861
+ // stream) is already covered by the stream-level error handler below.
1862
+ if (dlH2 !== stream) {
1863
+ dlH2.on("error", function (e) {
1864
+ if (capExceeded) return;
1865
+ if (observer) observer("error", { phase: "stream", message: e.message });
1866
+ _reject(_makeError(opts.errorClass, e.code || "H2_STREAM_ERROR", e.message, false));
1867
+ });
1868
+ }
1869
+
1870
+ dlH2.on("data", function (chunk) {
1702
1871
  if (capExceeded) return;
1703
1872
  try { collector.push(chunk); }
1704
1873
  catch (_e) {
@@ -1708,12 +1877,8 @@ function _requestH2(transport, u, opts) {
1708
1877
  "response body exceeds " + maxResponseBytes + " bytes", true));
1709
1878
  return;
1710
1879
  }
1711
- if (onChunkH2) {
1712
- try { onChunkH2(chunk); }
1713
- catch (_e) { /* operator-supplied hook — drop-silent */ }
1714
- }
1715
1880
  });
1716
- stream.on("end", function () {
1881
+ dlH2.on("end", function () {
1717
1882
  if (capExceeded) return;
1718
1883
  var buf = collector.result();
1719
1884
  if (observer) observer("response:end", {
@@ -1751,7 +1916,14 @@ function _requestH2(transport, u, opts) {
1751
1916
  signal.addEventListener("abort", onAbort, { once: true });
1752
1917
  }
1753
1918
 
1754
- if (opts.body && typeof opts.body.pipe === "function") {
1919
+ var ulStagesH2 = _uploadStages(throttleBps, uploadTransforms);
1920
+ if (opts.body != null && opts.body !== "" && ulStagesH2.length > 0) {
1921
+ _pipeThrottledUpload(opts.body, stream, ulStagesH2, null, function (e) {
1922
+ try { stream.close(http2.constants.NGHTTP2_INTERNAL_ERROR); } catch (_) { /* best-effort h2 stream cancel */ }
1923
+ _reject(_makeError(opts.errorClass, "REQ_BODY_ERROR",
1924
+ "request body stream error: " + e.message, false));
1925
+ });
1926
+ } else if (opts.body && typeof opts.body.pipe === "function") {
1755
1927
  opts.body.on("error", function (e) {
1756
1928
  try { stream.close(http2.constants.NGHTTP2_INTERNAL_ERROR); } catch (_) { /* best-effort h2 stream cancel */ }
1757
1929
  _reject(_makeError(opts.errorClass, "REQ_BODY_ERROR",
@@ -96,6 +96,7 @@
96
96
 
97
97
  var audit = require("./audit");
98
98
  var bCrypto = require("./crypto");
99
+ var numericBounds = require("./numeric-bounds");
99
100
  var { defineClass } = require("./framework-error");
100
101
  var IabTcfError = defineClass("IabTcfError", { alwaysPermanent: true });
101
102
 
@@ -521,7 +522,7 @@ function _idArray(x) {
521
522
  var seen = Object.create(null);
522
523
  var out = [];
523
524
  list.forEach(function (id) {
524
- if (typeof id !== "number" || !isFinite(id) || id < 1 || Math.floor(id) !== id) {
525
+ if (!numericBounds.isPositiveFiniteInt(id)) {
525
526
  throw IabTcfError.factory("iab-tcf/bad-value", "iabTcf.encode: vendor/purpose ids must be positive integers, got " + id);
526
527
  }
527
528
  if (!seen[id]) { seen[id] = 1; out.push(id); }
@@ -554,7 +555,7 @@ function _decisec(t) {
554
555
  function _bitWriter() {
555
556
  var bits = "";
556
557
  function writeInt(v, n) {
557
- if (typeof v !== "number" || !isFinite(v) || v < 0 || Math.floor(v) !== v) throw IabTcfError.factory("iab-tcf/bad-value", "iabTcf.encode: expected a non-negative integer, got " + v);
558
+ if (!numericBounds.isNonNegativeFiniteInt(v)) throw IabTcfError.factory("iab-tcf/bad-value", "iabTcf.encode: expected a non-negative integer, got " + v);
558
559
  if (v >= Math.pow(2, n)) throw IabTcfError.factory("iab-tcf/value-overflow", "iabTcf.encode: " + v + " does not fit in " + n + " bits");
559
560
  bits += v.toString(2).padStart(n, "0");
560
561
  }
@@ -22,6 +22,7 @@
22
22
 
23
23
  var validateOpts = require("./validate-opts");
24
24
  var bCrypto = require("./crypto");
25
+ var safeJson = require("./safe-json");
25
26
  var { defineClass } = require("./framework-error");
26
27
 
27
28
  var ImportmapError = defineClass("ImportmapError", { alwaysPermanent: true });
@@ -46,7 +47,9 @@ var ImportmapError = defineClass("ImportmapError", { alwaysPermanent: true });
46
47
  * "@org/lib": { url: "/static/lib.js", body: fileBytes },
47
48
  * },
48
49
  * });
49
- * res.end("<script type=\"importmap\">" + JSON.stringify(im) + "</script>");
50
+ * // Embed with the <script>-safe helper NEVER raw JSON.stringify, which
51
+ * // does not escape "</script>" in a module url and breaks out of the tag.
52
+ * res.end(b.importmapIntegrity.scriptTag(im));
50
53
  */
51
54
  function build(opts) {
52
55
  opts = validateOpts.requireObject(opts, "importmapIntegrity.build",
@@ -84,7 +87,44 @@ function build(opts) {
84
87
  return { imports: imports, integrity: integrity };
85
88
  }
86
89
 
90
+ /**
91
+ * @primitive b.importmapIntegrity.scriptTag
92
+ * @signature b.importmapIntegrity.scriptTag(importmap, opts?)
93
+ * @since 0.15.14
94
+ * @status stable
95
+ * @related b.importmapIntegrity.build, b.safeJson.stringifyForScript
96
+ *
97
+ * Render an import-map object (from `build`) as a ready-to-embed
98
+ * `<script type="importmap">…</script>` tag using the `<script>`-safe
99
+ * JSON serializer. Raw `JSON.stringify` does not escape `</script>` in a
100
+ * module url, so concatenating it into the page lets a `</script>` in a
101
+ * url close the element and inject markup — this escapes `< > &` (and the
102
+ * U+2028 / U+2029 separators) so no url can break out.
103
+ *
104
+ * @opts
105
+ * nonce: string, // CSP nonce added as nonce="…" on the <script>
106
+ *
107
+ * @example
108
+ * res.end(b.importmapIntegrity.scriptTag(im, { nonce: req.cspNonce }));
109
+ */
110
+ function scriptTag(importmap, opts) {
111
+ opts = opts || {};
112
+ var nonceAttr = "";
113
+ if (typeof opts.nonce === "string" && opts.nonce.length > 0) {
114
+ // The nonce is operator-supplied (a CSP per-request token); reject any
115
+ // value that could itself break the attribute rather than escape it.
116
+ if (/[^A-Za-z0-9+/=_-]/.test(opts.nonce)) {
117
+ throw new ImportmapError("importmap/bad-nonce",
118
+ "scriptTag: opts.nonce must be a base64/token string");
119
+ }
120
+ nonceAttr = ' nonce="' + opts.nonce + '"';
121
+ }
122
+ return '<script type="importmap"' + nonceAttr + '>' +
123
+ safeJson.stringifyForScript(importmap) + "</script>";
124
+ }
125
+
87
126
  module.exports = {
88
127
  build: build,
128
+ scriptTag: scriptTag,
89
129
  ImportmapError: ImportmapError,
90
130
  };
@@ -93,12 +93,15 @@ var REGIME_DEADLINES = Object.freeze({
93
93
  intermediate: C.TIME.hours(72),
94
94
  final: C.TIME.days(30),
95
95
  }),
96
- // DORA (EU Digital Operational Resilience Act) Article 19: initial
97
- // within 4h of classification, intermediate within 24h, final
98
- // within 1 month.
96
+ // DORA (EU Digital Operational Resilience Act) Art. 19 + RTS (EU)
97
+ // 2024/1772 Art. 5: initial within 4h of classifying the incident as
98
+ // major (outer bound 24h from awareness), intermediate within 72h of the
99
+ // initial notification, final within 1 month of the intermediate report.
100
+ // (intermediate was 24h here, contradicting lib/dora.js's 72h — the RTS
101
+ // value is 72h from the initial notification; aligned.)
99
102
  dora: Object.freeze({
100
103
  initial: C.TIME.hours(4),
101
- intermediate: C.TIME.hours(24),
104
+ intermediate: C.TIME.hours(72),
102
105
  final: C.TIME.days(30),
103
106
  }),
104
107
  // CRA (EU Cyber Resilience Act) Article 14: early warning within
@@ -206,7 +209,7 @@ function create(opts) {
206
209
  }
207
210
 
208
211
  async function _recordStage(incidentId, stage, payload) {
209
- if (!VALID_STAGES[stage]) {
212
+ if (!Object.prototype.hasOwnProperty.call(VALID_STAGES, stage)) {
210
213
  throw new IncidentReportError("incident-report/bad-stage",
211
214
  "incident.report._recordStage: stage must be one of " + Object.keys(VALID_STAGES).join(", "));
212
215
  }
@@ -358,7 +361,7 @@ function createDeadlineClock(opts) {
358
361
  function untrack(id) { return tracked.delete(id); }
359
362
 
360
363
  function acknowledgeSubmission(id, stage, info) {
361
- if (!VALID_STAGES[stage]) {
364
+ if (!Object.prototype.hasOwnProperty.call(VALID_STAGES, stage)) {
362
365
  throw new IncidentReportError("incident-report/bad-stage",
363
366
  "createDeadlineClock.acknowledgeSubmission: stage must be one of " + Object.keys(VALID_STAGES).join(", "));
364
367
  }
@@ -157,7 +157,7 @@ function apply(doc, operations) {
157
157
  var work = structuredClone(doc);
158
158
  for (var i = 0; i < operations.length; i += 1) {
159
159
  var op = operations[i];
160
- if (!op || typeof op !== "object" || typeof op.op !== "string" || !OPS[op.op]) {
160
+ if (!op || typeof op !== "object" || typeof op.op !== "string" || !Object.prototype.hasOwnProperty.call(OPS, op.op)) {
161
161
  throw new JsonPatchError("json-patch/bad-op", "jsonPatch.apply: operations[" + i + "] has an invalid 'op'");
162
162
  }
163
163
  if (typeof op.path !== "string") throw new JsonPatchError("json-patch/bad-op", "jsonPatch.apply: operations[" + i + "] is missing 'path'");
@@ -35,6 +35,7 @@ var { defineClass } = require("./framework-error");
35
35
  var JsonPathError = defineClass("JsonPathError", { alwaysPermanent: true });
36
36
 
37
37
  var MAX_DESCEND_NODES = 1000000; // DoS ceiling on nodes visited by a descendant walk
38
+ var MAX_TOTAL_NODES = 1000000; // DoS ceiling on the running nodelist across ALL segments (chained wildcard/slice/filter cross-product)
38
39
 
39
40
  // ---------------------------------------------------------------------------
40
41
  // Parser — recursive descent over the RFC 9535 ABNF.
@@ -46,7 +47,20 @@ function _isDigit(c) { return c >= "0" && c <= "9"; }
46
47
  function _isNameFirst(c) { var cc = c.charCodeAt(0); return (c >= "A" && c <= "Z") || (c >= "a" && c <= "z") || c === "_" || cc >= 0x80; }
47
48
  function _isNameChar(c) { return _isNameFirst(c) || _isDigit(c); }
48
49
 
49
- function _Parser(s) { this.s = s; this.i = 0; }
50
+ function _Parser(s) { this.s = s; this.i = 0; this._depth = 0; }
51
+
52
+ // Nesting-depth cap for the filter-expression recursion (parens + `!`). Without
53
+ // it, a deeply-nested filter like `?(((((...)))))` recurses until V8 throws a
54
+ // raw RangeError ("Maximum call stack size exceeded") that escapes JsonPathError
55
+ // handling — a DoS / unhandled-crash lever on attacker-supplied JSONPath.
56
+ var MAX_FILTER_DEPTH = 200;
57
+ _Parser.prototype._descend = function () {
58
+ if (++this._depth > MAX_FILTER_DEPTH) {
59
+ throw new JsonPathError("json-path/filter-too-deep",
60
+ "jsonPath: filter expression nesting exceeds " + MAX_FILTER_DEPTH);
61
+ }
62
+ };
63
+ _Parser.prototype._ascend = function () { this._depth -= 1; };
50
64
  _Parser.prototype.err = function (msg) { throw new JsonPathError("json-path/invalid", "jsonPath: " + msg + " at index " + this.i); };
51
65
  _Parser.prototype.peek = function () { return this.i < this.s.length ? this.s.charAt(this.i) : ""; };
52
66
  _Parser.prototype.eat = function (c) { if (this.peek() !== c) this.err("expected '" + c + "'"); this.i += 1; };
@@ -226,9 +240,9 @@ _Parser.prototype.parseLogicalAnd = function () {
226
240
  };
227
241
  _Parser.prototype.parseBasic = function () {
228
242
  this.skipBlank();
229
- if (this.peek() === "!") { this.i += 1; this.skipBlank(); var inner = this.parseBasic(); this._requireTestable(inner); return { type: "not", e: inner, vtype: "logical" }; }
243
+ if (this.peek() === "!") { this.i += 1; this.skipBlank(); this._descend(); var inner = this.parseBasic(); this._ascend(); this._requireTestable(inner); return { type: "not", e: inner, vtype: "logical" }; }
230
244
  if (this.peek() === "(") {
231
- this.i += 1; this.skipBlank(); var e = this.parseLogicalOr(); this.skipBlank(); this.eat(")");
245
+ this.i += 1; this.skipBlank(); this._descend(); var e = this.parseLogicalOr(); this._ascend(); this.skipBlank(); this.eat(")");
232
246
  return e;
233
247
  }
234
248
  // comparison or test
@@ -436,6 +450,13 @@ function _evalSegments(segments, root) {
436
450
  base = acc;
437
451
  }
438
452
  base.forEach(function (nd) { seg.selectors.forEach(function (sel) { _applySelector(sel, nd, root, next); }); });
453
+ // Cap the running nodelist across the WHOLE query, not just per descendant
454
+ // walk: chained wildcard/slice/filter selectors multiply the nodelist each
455
+ // segment ([*][*][*]…), an OOM lever the per-`_descend` budget never sees.
456
+ if (next.length > MAX_TOTAL_NODES) {
457
+ throw new JsonPathError("json-path/too-large",
458
+ "jsonPath: nodelist exceeded " + MAX_TOTAL_NODES + " nodes (chained selector cross-product)");
459
+ }
439
460
  nodes = next;
440
461
  }
441
462
  return nodes;
@@ -58,7 +58,7 @@ function _checkSchema(schema, root, isRoot) {
58
58
  if (!_isPlainObject(schema)) throw new JtdError("jtd/bad-schema", "jtd: schema must be an object");
59
59
  if (!isRoot && Object.prototype.hasOwnProperty.call(schema, "definitions")) throw new JtdError("jtd/bad-schema", "jtd: 'definitions' is allowed only at the root");
60
60
  Object.keys(schema).forEach(function (k) {
61
- if (FORM_KEYWORDS.indexOf(k) === -1 && !SHARED_KEYWORDS[k] && k !== "additionalProperties" && k !== "mapping") throw new JtdError("jtd/bad-schema", "jtd: unknown keyword '" + k + "'");
61
+ if (FORM_KEYWORDS.indexOf(k) === -1 && !Object.prototype.hasOwnProperty.call(SHARED_KEYWORDS, k) && k !== "additionalProperties" && k !== "mapping") throw new JtdError("jtd/bad-schema", "jtd: unknown keyword '" + k + "'");
62
62
  });
63
63
  if (Object.prototype.hasOwnProperty.call(schema, "nullable") && typeof schema.nullable !== "boolean") throw new JtdError("jtd/bad-schema", "jtd: 'nullable' must be a boolean");
64
64
  if (Object.prototype.hasOwnProperty.call(schema, "metadata") && !_isPlainObject(schema.metadata)) throw new JtdError("jtd/bad-schema", "jtd: 'metadata' must be an object");
@@ -75,7 +75,7 @@ function _checkSchema(schema, root, isRoot) {
75
75
  if ("ref" in schema) {
76
76
  if (typeof schema.ref !== "string" || !root.definitions || !Object.prototype.hasOwnProperty.call(root.definitions, schema.ref)) throw new JtdError("jtd/bad-schema", "jtd: 'ref' must name a key in the root definitions");
77
77
  }
78
- if ("type" in schema && !TYPES[schema.type]) throw new JtdError("jtd/bad-schema", "jtd: unknown type '" + schema.type + "'");
78
+ if ("type" in schema && !Object.prototype.hasOwnProperty.call(TYPES, schema.type)) throw new JtdError("jtd/bad-schema", "jtd: unknown type '" + schema.type + "'");
79
79
  if ("enum" in schema) {
80
80
  if (!Array.isArray(schema.enum) || schema.enum.length === 0) throw new JtdError("jtd/bad-schema", "jtd: 'enum' must be a non-empty array");
81
81
  var seen = Object.create(null);
@@ -210,19 +210,34 @@ function create(opts) {
210
210
  _ensureSchema();
211
211
  var hash = _hashSubject(sid);
212
212
  var placeSelBuilt = sql.select(HOLD_TABLE, SQL_OPTS)
213
- .columns(["placedAt"])
213
+ .columns(["placedAt", "retainUntil"])
214
214
  .where("subjectIdHash", hash)
215
215
  .toSql();
216
216
  var placeSelStmt = db.prepare(placeSelBuilt.sql);
217
217
  var existing = placeSelStmt.get.apply(placeSelStmt, placeSelBuilt.params);
218
+ var nowMs = Date.now();
219
+ var renewedFromLapsed = false;
218
220
  if (existing) {
219
- _emit("legalhold.place_rejected",
220
- { subjectId: sid, reason: "already-held",
221
- existingSince: existing.placedAt },
222
- "denied");
223
- return { error: "already-held", placedAt: existing.placedAt };
221
+ // A LAPSED hold (retainUntil sunset already passed → isHeld() is already
222
+ // false) must not block a fresh placement: otherwise a subject whose hold
223
+ // expired cannot be re-held when new litigation arises, leaving the data
224
+ // both unprotected (isHeld false) and erasable by retention. Replace the
225
+ // lapsed row with the new hold. An ACTIVE hold still rejects as before.
226
+ var existingLapsed = existing.retainUntil && existing.retainUntil < nowMs;
227
+ if (!existingLapsed) {
228
+ _emit("legalhold.place_rejected",
229
+ { subjectId: sid, reason: "already-held",
230
+ existingSince: existing.placedAt },
231
+ "denied");
232
+ return { error: "already-held", placedAt: existing.placedAt };
233
+ }
234
+ renewedFromLapsed = true;
235
+ var lapseDelBuilt = sql.delete(HOLD_TABLE, SQL_OPTS)
236
+ .where("subjectIdHash", hash)
237
+ .toSql();
238
+ var lapseDelStmt = db.prepare(lapseDelBuilt.sql);
239
+ lapseDelStmt.run.apply(lapseDelStmt, lapseDelBuilt.params);
224
240
  }
225
- var nowMs = Date.now();
226
241
  var placeInsBuilt = sql.insert(HOLD_TABLE, SQL_OPTS)
227
242
  .values(cryptoField.sealRow(HOLD_TABLE, {
228
243
  subjectIdHash: hash,
@@ -242,9 +257,10 @@ function create(opts) {
242
257
  citation: args.citation || null,
243
258
  retainUntil: args.retainUntil || null,
244
259
  placedBy: args.placedBy || null,
260
+ renewedFromLapsed: renewedFromLapsed,
245
261
  knownCitation: args.citation && KNOWN_CITATIONS.indexOf(args.citation) !== -1 },
246
262
  "success");
247
- return { placed: true, placedAt: nowMs };
263
+ return { placed: true, placedAt: nowMs, renewedFromLapsed: renewedFromLapsed };
248
264
  }
249
265
 
250
266
  function release(subjectId, args) {