@blamejs/blamejs-shop 0.5.12 → 0.5.13

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 (521) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +632 -416
  4. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
  5. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
  6. package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
  7. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  8. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
  9. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
  10. package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
  11. package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
  12. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
  13. package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
  14. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
  15. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  16. package/lib/vendor/blamejs/.gitignore +2 -0
  17. package/lib/vendor/blamejs/CHANGELOG.md +122 -0
  18. package/lib/vendor/blamejs/NOTICE +26 -1
  19. package/lib/vendor/blamejs/SECURITY.md +1 -1
  20. package/lib/vendor/blamejs/api-snapshot.json +207 -5
  21. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
  22. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
  25. package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
  26. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  27. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
  28. package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
  29. package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
  30. package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
  31. package/lib/vendor/blamejs/index.js +6 -0
  32. package/lib/vendor/blamejs/lib/a2a.js +4 -4
  33. package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
  34. package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
  35. package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
  36. package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
  37. package/lib/vendor/blamejs/lib/archive-read.js +8 -0
  38. package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
  39. package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
  40. package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
  41. package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
  42. package/lib/vendor/blamejs/lib/audit.js +71 -8
  43. package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
  44. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
  45. package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
  46. package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
  47. package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
  48. package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
  49. package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
  50. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
  51. package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
  52. package/lib/vendor/blamejs/lib/backup/index.js +16 -5
  53. package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
  54. package/lib/vendor/blamejs/lib/base32.js +21 -0
  55. package/lib/vendor/blamejs/lib/break-glass.js +19 -10
  56. package/lib/vendor/blamejs/lib/bundler.js +5 -1
  57. package/lib/vendor/blamejs/lib/cache-status.js +3 -7
  58. package/lib/vendor/blamejs/lib/calendar.js +21 -1
  59. package/lib/vendor/blamejs/lib/cbor.js +12 -1
  60. package/lib/vendor/blamejs/lib/cert.js +29 -11
  61. package/lib/vendor/blamejs/lib/cli.js +94 -24
  62. package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
  63. package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
  64. package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
  65. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
  66. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
  67. package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
  68. package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
  69. package/lib/vendor/blamejs/lib/content-digest.js +2 -1
  70. package/lib/vendor/blamejs/lib/cookies.js +13 -3
  71. package/lib/vendor/blamejs/lib/cose.js +31 -16
  72. package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
  73. package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
  74. package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
  75. package/lib/vendor/blamejs/lib/crypto.js +314 -19
  76. package/lib/vendor/blamejs/lib/csp.js +11 -3
  77. package/lib/vendor/blamejs/lib/daemon.js +270 -24
  78. package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
  79. package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
  80. package/lib/vendor/blamejs/lib/db-query.js +34 -7
  81. package/lib/vendor/blamejs/lib/db.js +18 -6
  82. package/lib/vendor/blamejs/lib/dbsc.js +17 -0
  83. package/lib/vendor/blamejs/lib/dev.js +21 -2
  84. package/lib/vendor/blamejs/lib/dsr.js +157 -102
  85. package/lib/vendor/blamejs/lib/external-db.js +41 -2
  86. package/lib/vendor/blamejs/lib/file-upload.js +25 -7
  87. package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
  88. package/lib/vendor/blamejs/lib/forms.js +113 -27
  89. package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
  90. package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
  91. package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
  92. package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
  93. package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
  94. package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
  95. package/lib/vendor/blamejs/lib/guard-html.js +26 -53
  96. package/lib/vendor/blamejs/lib/guard-image.js +24 -5
  97. package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
  98. package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
  99. package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
  100. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
  101. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
  102. package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
  105. package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
  106. package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
  107. package/lib/vendor/blamejs/lib/guard-time.js +1 -1
  108. package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
  109. package/lib/vendor/blamejs/lib/html-balance.js +3 -3
  110. package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
  111. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
  112. package/lib/vendor/blamejs/lib/http-client.js +39 -7
  113. package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
  114. package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
  115. package/lib/vendor/blamejs/lib/i18n.js +35 -21
  116. package/lib/vendor/blamejs/lib/incident-report.js +8 -1
  117. package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
  118. package/lib/vendor/blamejs/lib/json-path.js +23 -1
  119. package/lib/vendor/blamejs/lib/jwk.js +20 -3
  120. package/lib/vendor/blamejs/lib/link-header.js +2 -1
  121. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
  123. package/lib/vendor/blamejs/lib/log-stream.js +8 -3
  124. package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
  125. package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
  126. package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
  128. package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
  129. package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
  130. package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
  131. package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
  132. package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
  133. package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
  134. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
  136. package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
  137. package/lib/vendor/blamejs/lib/mail.js +15 -5
  138. package/lib/vendor/blamejs/lib/metrics.js +268 -63
  139. package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
  140. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
  141. package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
  142. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
  143. package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
  144. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
  145. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
  146. package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
  147. package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
  148. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
  149. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
  150. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
  151. package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
  152. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
  153. package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
  154. package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
  155. package/lib/vendor/blamejs/lib/network-dns.js +21 -2
  156. package/lib/vendor/blamejs/lib/network-tls.js +69 -7
  157. package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
  158. package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
  159. package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
  160. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
  161. package/lib/vendor/blamejs/lib/outbox.js +1 -1
  162. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
  163. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
  164. package/lib/vendor/blamejs/lib/permissions.js +6 -3
  165. package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
  166. package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
  167. package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
  168. package/lib/vendor/blamejs/lib/pubsub.js +20 -9
  169. package/lib/vendor/blamejs/lib/queue-local.js +8 -1
  170. package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
  171. package/lib/vendor/blamejs/lib/redact.js +54 -0
  172. package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
  173. package/lib/vendor/blamejs/lib/restore.js +19 -0
  174. package/lib/vendor/blamejs/lib/retention.js +12 -4
  175. package/lib/vendor/blamejs/lib/router.js +60 -6
  176. package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
  177. package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
  178. package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
  179. package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
  180. package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
  181. package/lib/vendor/blamejs/lib/safe-object.js +80 -0
  182. package/lib/vendor/blamejs/lib/safe-path.js +52 -4
  183. package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
  184. package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
  185. package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
  186. package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
  187. package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
  188. package/lib/vendor/blamejs/lib/scheduler.js +8 -1
  189. package/lib/vendor/blamejs/lib/security-assert.js +6 -6
  190. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
  191. package/lib/vendor/blamejs/lib/self-update.js +517 -87
  192. package/lib/vendor/blamejs/lib/server-timing.js +2 -4
  193. package/lib/vendor/blamejs/lib/session.js +34 -12
  194. package/lib/vendor/blamejs/lib/sql.js +15 -1
  195. package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
  196. package/lib/vendor/blamejs/lib/static.js +55 -13
  197. package/lib/vendor/blamejs/lib/storage.js +8 -2
  198. package/lib/vendor/blamejs/lib/subject.js +6 -1
  199. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
  200. package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
  201. package/lib/vendor/blamejs/lib/tsa.js +34 -13
  202. package/lib/vendor/blamejs/lib/uri-template.js +8 -1
  203. package/lib/vendor/blamejs/lib/vault/index.js +13 -0
  204. package/lib/vendor/blamejs/lib/vc.js +44 -5
  205. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
  206. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
  207. package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
  208. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
  209. package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
  210. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
  212. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
  213. package/lib/vendor/blamejs/lib/watcher.js +89 -17
  214. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
  215. package/lib/vendor/blamejs/lib/webhook.js +12 -2
  216. package/lib/vendor/blamejs/lib/ws-client.js +32 -1
  217. package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
  218. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
  219. package/lib/vendor/blamejs/package-lock.json +2 -2
  220. package/lib/vendor/blamejs/package.json +1 -1
  221. package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
  222. package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
  223. package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
  224. package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
  225. package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
  226. package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
  227. package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
  228. package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
  229. package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
  230. package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
  231. package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
  232. package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
  233. package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
  234. package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
  235. package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
  236. package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
  237. package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
  238. package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
  239. package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
  240. package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
  241. package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
  242. package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
  243. package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
  244. package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
  245. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
  246. package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
  247. package/lib/vendor/blamejs/socket.yml +94 -0
  248. package/lib/vendor/blamejs/test/00-primitives.js +605 -0
  249. package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
  250. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
  251. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
  252. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
  253. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
  254. package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
  255. package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
  256. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
  257. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
  258. package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
  259. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
  262. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
  268. package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
  284. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
  293. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
  294. package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
  302. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
  307. package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
  315. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
  317. package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
  318. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
  319. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
  320. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
  321. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
  322. package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
  323. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
  324. package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
  325. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
  326. package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
  327. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
  328. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
  329. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
  330. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
  331. package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
  334. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
  335. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
  336. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
  337. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
  341. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
  342. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
  346. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
  347. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
  348. package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
  349. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
  376. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
  388. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
  389. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
  390. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
  391. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
  392. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
  393. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
  395. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
  396. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
  397. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
  398. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
  399. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
  400. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
  401. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
  402. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
  403. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
  404. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
  405. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
  406. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
  407. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
  408. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
  409. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
  410. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
  411. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
  412. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
  413. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
  414. package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
  415. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
  416. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
  417. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
  418. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
  419. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
  420. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
  421. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
  422. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
  423. package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
  424. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
  425. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
  426. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
  427. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
  428. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
  429. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
  430. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
  431. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
  432. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
  433. package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
  434. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
  435. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
  436. package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
  437. package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
  438. package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
  439. package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
  440. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
  441. package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
  442. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
  443. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
  444. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
  445. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
  446. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
  447. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
  448. package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
  449. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
  450. package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
  451. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
  452. package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
  453. package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
  454. package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
  455. package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
  456. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
  457. package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
  458. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
  459. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
  460. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
  461. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
  462. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
  463. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
  464. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
  465. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
  466. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
  467. package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
  468. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
  469. package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
  470. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
  471. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
  472. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
  473. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
  474. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
  475. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
  476. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
  477. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
  478. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
  479. package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
  480. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
  481. package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
  482. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
  483. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
  484. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
  485. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
  486. package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
  487. package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
  488. package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
  489. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
  490. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
  491. package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
  492. package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
  493. package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
  494. package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
  495. package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
  496. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
  497. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
  498. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
  499. package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
  500. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
  501. package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
  502. package/lib/vendor/blamejs/test/smoke.js +2 -0
  503. package/package.json +1 -1
  504. package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
  505. package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
  506. package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
  507. package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
  508. package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
  509. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
  510. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
  511. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
  512. package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
  513. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
  514. package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
  515. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
  516. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
  517. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
  518. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
  519. package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
  520. package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
  521. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
@@ -0,0 +1,1277 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) blamejs contributors
3
+ "use strict";
4
+ /**
5
+ * b.router — coverage for the registration, dispatch, introspection, and
6
+ * static-file surfaces not exercised by the focused router test files
7
+ * (router-use-path-scope / router-cross-origin-redirect / router-body-
8
+ * validation / router-tls0rtt).
9
+ *
10
+ * Drives the public API only — b.router.create(...), the route-registration
11
+ * verbs, r.handle(req, res) with in-memory request/response fakes, and a
12
+ * real in-process listen(0) server for the response-helper wiring
13
+ * (res.json / res.status / res.redirect / errorHandler / 0-RTT gate) that
14
+ * is only attached inside listen(). No external network / DB backend.
15
+ *
16
+ * Validates:
17
+ * - compilePattern registration-time refusals (empty / non-string /
18
+ * over-length pattern, empty parameter name)
19
+ * - _registerRoute CVE-2026-4923 asterisk-flood refusal
20
+ * - route-spec validation (unknown key, non-schema body/query/params/
21
+ * response, malformed tags)
22
+ * - dispatch: method-mismatch → 404, default vs custom notFound, param
23
+ * capture + req.routePattern, trailing-slash no-match, multi-handler
24
+ * fall-through, middleware next() semantics, req.query population,
25
+ * the HashDoS query-key cap
26
+ * - schema validator query/params paths + response-validation throw mode
27
+ * - inspectRoutes / openapi / getReservedSlugs introspection
28
+ * - ws() registration validation + activeWebSockets / closeWebSockets
29
+ * - serveStatic next() bypass branches + a real served file
30
+ * - listen() response helpers end-to-end on a live localhost server
31
+ */
32
+
33
+ var http = require("node:http");
34
+ var net = require("node:net");
35
+ var crypto = require("node:crypto");
36
+ var fs = require("node:fs");
37
+ var os = require("node:os");
38
+ var nodePath = require("node:path");
39
+
40
+ var http2 = require("node:http2");
41
+ var C = require("../../lib/constants");
42
+ var mtlsEngine = require("../../lib/mtls-engine-default");
43
+ var compliance = require("../../lib/compliance");
44
+ var pki = require("../../lib/vendor/pki.cjs");
45
+
46
+ var helpers = require("../helpers");
47
+ var b = helpers.b;
48
+ var check = helpers.check;
49
+ var s = b.safeSchema;
50
+
51
+ function _req(method, url, headers) {
52
+ return { method: method, url: url, headers: Object.assign({ host: "localhost" }, headers || {}) };
53
+ }
54
+
55
+ function _res() {
56
+ var res = {
57
+ statusCode: 0,
58
+ headersSent: false,
59
+ writableEnded: false,
60
+ _body: "",
61
+ _headers: null,
62
+ writeHead: function (status, headers) {
63
+ res.statusCode = status;
64
+ res._headers = headers || {};
65
+ res.headersSent = true;
66
+ },
67
+ end: function (chunk) {
68
+ if (chunk !== undefined) res._body += chunk;
69
+ res.writableEnded = true;
70
+ },
71
+ };
72
+ return res;
73
+ }
74
+
75
+ function _throwMsg(fn) {
76
+ try { fn(); return null; }
77
+ catch (e) { return (e && e.message) || "threw"; }
78
+ }
79
+
80
+ // ---- compilePattern registration-time refusals ----
81
+
82
+ function testPatternValidation() {
83
+ check("get('') refuses empty pattern",
84
+ /non-empty string/.test(_throwMsg(function () { b.router.create().get("", function () {}); })));
85
+ check("get(123) refuses non-string pattern",
86
+ /non-empty string/.test(_throwMsg(function () { b.router.create().get(123, function () {}); })));
87
+ var long = "/" + "a".repeat(1030);
88
+ check("get(<1031-char pattern>) refuses over-length pattern",
89
+ /exceeds 1024 chars/.test(_throwMsg(function () { b.router.create().get(long, function () {}); })));
90
+ check("get('/users/:') refuses empty parameter name",
91
+ /empty parameter name/.test(_throwMsg(function () { b.router.create().get("/users/:", function () {}); })));
92
+ }
93
+
94
+ function testAsteriskFloodRefused() {
95
+ check("get('/a/****/b') refused (CVE-2026-4923, 4 asterisks)",
96
+ /CVE-2026-4923/.test(_throwMsg(function () { b.router.create().get("/a/****/b", function () {}); })));
97
+ check("get('/a/***/b') allowed (3 asterisks under the cap)",
98
+ _throwMsg(function () { b.router.create().get("/a/***/b", function () {}); }) === null);
99
+ }
100
+
101
+ function testRouteSpecValidation() {
102
+ check("spec with unknown key refused",
103
+ /unknown spec key 'bogus'/.test(_throwMsg(function () {
104
+ b.router.create().get("/x", { bogus: 1 }, function () {});
105
+ })));
106
+ check("spec.body not a schema refused",
107
+ /spec\.body must be a b\.safeSchema/.test(_throwMsg(function () {
108
+ b.router.create().get("/x", { body: {} }, function () {});
109
+ })));
110
+ check("spec.query not a schema refused",
111
+ /spec\.query must be a b\.safeSchema/.test(_throwMsg(function () {
112
+ b.router.create().get("/x", { query: { safeParse: 1 } }, function () {});
113
+ })));
114
+ check("spec.response not a schema refused",
115
+ /spec\.response must be a b\.safeSchema/.test(_throwMsg(function () {
116
+ b.router.create().get("/x", { response: 5 }, function () {});
117
+ })));
118
+ check("spec.tags not an array refused",
119
+ /spec\.tags must be an array of strings/.test(_throwMsg(function () {
120
+ b.router.create().get("/x", { tags: "nope" }, function () {});
121
+ })));
122
+ check("spec.tags with non-string entries refused",
123
+ /spec\.tags must be an array of strings/.test(_throwMsg(function () {
124
+ b.router.create().get("/x", { tags: [1, 2] }, function () {});
125
+ })));
126
+ }
127
+
128
+ // ---- dispatch ----
129
+
130
+ async function testMethodMismatchFallsToNotFound() {
131
+ var r = b.router.create();
132
+ var ran = false;
133
+ r.get("/x", function (req, res) { ran = true; res.writeHead(200); res.end("get"); });
134
+ var res = _res();
135
+ await r.handle(_req("POST", "/x"), res);
136
+ check("POST to a GET-only path → 404 (method not matched, no 405)",
137
+ res.statusCode === 404 && ran === false);
138
+ }
139
+
140
+ async function testDefaultNotFoundBody() {
141
+ var r = b.router.create();
142
+ var res = _res();
143
+ await r.handle(_req("GET", "/nope"), res);
144
+ check("default notFound → 404 with the framework HTML body",
145
+ res.statusCode === 404 && res._body === "<h1>404 Not Found</h1>");
146
+ }
147
+
148
+ async function testCustomNotFound() {
149
+ var r = b.router.create();
150
+ var sawReq = false;
151
+ r.onNotFound(function (req, res) { sawReq = !!req; res.writeHead(404); res.end("custom-nf"); });
152
+ var res = _res();
153
+ await r.handle(_req("GET", "/nope"), res);
154
+ check("onNotFound handler runs on no-match",
155
+ res.statusCode === 404 && res._body === "custom-nf" && sawReq === true);
156
+ }
157
+
158
+ async function testParamCaptureAndRoutePattern() {
159
+ var r = b.router.create();
160
+ var seen = null, pattern = null;
161
+ r.get("/users/:id/posts/:pid", function (req, res) {
162
+ seen = req.params; pattern = req.routePattern;
163
+ res.writeHead(200); res.end("ok");
164
+ });
165
+ var res = _res();
166
+ await r.handle(_req("GET", "/users/42/posts/99"), res);
167
+ check("named params captured onto req.params",
168
+ seen && seen.id === "42" && seen.pid === "99");
169
+ check("req.routePattern exposes the route template (not the concrete URL)",
170
+ pattern === "/users/:id/posts/:pid");
171
+ }
172
+
173
+ async function testTrailingSlashParamNoMatch() {
174
+ var r = b.router.create();
175
+ var ran = false;
176
+ r.get("/users/:id", function (req, res) { ran = true; res.writeHead(200); res.end("u"); });
177
+ var res = _res();
178
+ await r.handle(_req("GET", "/users/"), res);
179
+ check("'/users/' does NOT match '/users/:id' (empty param segment) → 404",
180
+ res.statusCode === 404 && ran === false);
181
+ }
182
+
183
+ async function testMultiHandlerFallThrough() {
184
+ var r = b.router.create();
185
+ var order = [];
186
+ r.get("/m",
187
+ function (req, res) { order.push("h1"); },
188
+ function (req, res) { order.push("h2"); res.writeHead(200); res.end("done"); });
189
+ var res = _res();
190
+ await r.handle(_req("GET", "/m"), res);
191
+ check("two terminal handlers on one route both run in order",
192
+ order.join(",") === "h1,h2" && res.statusCode === 200);
193
+ }
194
+
195
+ async function testInRouteMiddlewareNextSemantics() {
196
+ var r = b.router.create();
197
+ var terminalRan = false;
198
+ r.get("/g",
199
+ function gate(req, res, next) { /* no next() — refuse */ res.writeHead(403); res.end("deny"); },
200
+ function terminal(req, res) { terminalRan = true; res.writeHead(200); res.end("ok"); });
201
+ var res = _res();
202
+ await r.handle(_req("GET", "/g"), res);
203
+ check("in-route middleware that omits next() halts the chain",
204
+ res.statusCode === 403 && terminalRan === false);
205
+
206
+ var r2 = b.router.create();
207
+ var order = [];
208
+ r2.get("/g2",
209
+ function gate(req, res, next) { order.push("gate"); next(); },
210
+ function terminal(req, res) { order.push("terminal"); res.writeHead(200); res.end("ok"); });
211
+ var res2 = _res();
212
+ await r2.handle(_req("GET", "/g2"), res2);
213
+ check("in-route middleware that calls next() proceeds to the terminal handler",
214
+ order.join(",") === "gate,terminal" && res2.statusCode === 200);
215
+ }
216
+
217
+ async function testGlobalMwEndsResponseWithNextStopsDispatch() {
218
+ var r = b.router.create();
219
+ var routeRan = false;
220
+ r.use(function (req, res, next) { res.writeHead(200); res.end("mw"); next(); });
221
+ r.get("/f", function (req, res) { routeRan = true; res.writeHead(200); res.end("route"); });
222
+ var res = _res();
223
+ await r.handle(_req("GET", "/f"), res);
224
+ check("a global middleware that ends the response short-circuits dispatch even if it calls next()",
225
+ routeRan === false && res._body === "mw");
226
+ }
227
+
228
+ async function testQueryPopulated() {
229
+ var r = b.router.create();
230
+ var seen = null;
231
+ r.get("/search", function (req, res) { seen = req.query; res.writeHead(200); res.end("ok"); });
232
+ var res = _res();
233
+ await r.handle(_req("GET", "/search?q=hello&limit=5"), res);
234
+ check("req.query is populated from the URL search string",
235
+ seen && seen.q === "hello" && seen.limit === "5");
236
+ }
237
+
238
+ async function testQueryKeyCap() {
239
+ var r = b.router.create();
240
+ var ran = false;
241
+ r.get("/q", function (req, res) { ran = true; res.writeHead(200); res.end("ok"); });
242
+ var parts = [];
243
+ for (var i = 0; i < 1001; i++) parts.push("k" + i + "=v");
244
+ var res = _res();
245
+ await r.handle(_req("GET", "/q?" + parts.join("&")), res);
246
+ check("HashDoS query-key cap: 1001 distinct keys → 400 before dispatch",
247
+ res.statusCode === 400 && ran === false && /too many query keys/.test(res._body));
248
+ }
249
+
250
+ // ---- schema + response validators ----
251
+
252
+ async function testQuerySchemaValidation() {
253
+ var r = b.router.create();
254
+ var handlerRan = false;
255
+ r.get("/search", { query: s.object({ q: s.string() }) }, function (req, res) {
256
+ handlerRan = true; res.writeHead(200); res.end("ok");
257
+ });
258
+
259
+ var ok = _res();
260
+ await r.handle(_req("GET", "/search?q=abc"), ok);
261
+ check("valid query → 200", ok.statusCode === 200 && handlerRan === true);
262
+
263
+ var bad = _res();
264
+ handlerRan = false;
265
+ await r.handle(_req("GET", "/search"), bad); // q omitted
266
+ check("missing required query field → 400 with where:query",
267
+ bad.statusCode === 400 && /"where":"query"/.test(bad._body) && handlerRan === false);
268
+ }
269
+
270
+ async function testParamsSchemaValidation() {
271
+ var r = b.router.create();
272
+ var seen = null;
273
+ r.get("/n/:count", { params: s.object({ count: s.string() }) }, function (req, res) {
274
+ seen = req.params; res.writeHead(200); res.end("ok");
275
+ });
276
+ var res = _res();
277
+ await r.handle(_req("GET", "/n/7"), res);
278
+ check("params schema runs and the handler sees the parsed params",
279
+ res.statusCode === 200 && seen && seen.count === "7");
280
+ }
281
+
282
+ async function testResponseValidatorThrowMode() {
283
+ var r = b.router.create();
284
+ r.get("/rv", { response: s.object({ ok: s.boolean() }), validateResponse: "throw" },
285
+ function (req, res) { res.json({ ok: "not-a-boolean" }); });
286
+ var res = _res();
287
+ res.json = function (v) { res.writeHead(200); res.end(JSON.stringify(v)); };
288
+ var threw = null;
289
+ try { await r.handle(_req("GET", "/rv"), res); } catch (e) { threw = e; }
290
+ check("response-validation throw mode surfaces a drift error out of res.json",
291
+ threw && /response-validation failed/.test(threw.message));
292
+ }
293
+
294
+ // ---- introspection ----
295
+
296
+ function testInspectRoutes() {
297
+ var r = b.router.create();
298
+ r.get("/u/:id", { description: "desc", tags: ["t"], summary: "sum" }, function () {});
299
+ r.post("/plain", function () {});
300
+ var rows = r.inspectRoutes();
301
+ check("inspectRoutes returns one row per registered route", rows.length === 2);
302
+ var specRow = rows[0];
303
+ check("inspectRoutes surfaces method + pattern + description",
304
+ specRow.method === "GET" && specRow.pattern === "/u/:id" && specRow.description === "desc");
305
+ check("inspectRoutes surfaces the spec tags + summary",
306
+ specRow.spec && specRow.spec.tags.join(",") === "t" && specRow.spec.summary === "sum");
307
+ check("inspectRoutes reports a plain route's spec as null",
308
+ rows[1].spec === null && rows[1].method === "POST");
309
+ }
310
+
311
+ function testOpenapi() {
312
+ var r = b.router.create();
313
+ r.get("/users/:id", {
314
+ summary: "Get user", tags: ["users"], description: "d",
315
+ queryJsonSchema: { properties: { q: { type: "string" } }, required: ["q"] },
316
+ responseJsonSchema: { type: "object" },
317
+ }, function () {});
318
+ r.post("/users/:id", { bodyJsonSchema: { type: "object" } }, function () {});
319
+ r.get("/safe", { body: s.object({ a: s.string() }) }, function () {});
320
+ r.put("/plain", function () {});
321
+
322
+ var docDefault = b.router.create().openapi();
323
+ check("openapi() defaults info to the framework placeholder",
324
+ docDefault.openapi === "3.0.3" &&
325
+ docDefault.info.title === "blamejs app" && docDefault.info.version === "0.0.0");
326
+
327
+ var doc = r.openapi({ info: { title: "T", version: "1.0" } });
328
+ check("openapi() passes custom info through", doc.info.title === "T" && doc.info.version === "1.0");
329
+ check("openapi() converts ':id' path params to '{id}' and merges methods on one path",
330
+ doc.paths["/users/{id}"] &&
331
+ !!doc.paths["/users/{id}"].get && !!doc.paths["/users/{id}"].post);
332
+
333
+ var getOp = doc.paths["/users/{id}"].get;
334
+ var pathParam = getOp.parameters.filter(function (p) { return p.in === "path"; })[0];
335
+ var queryParam = getOp.parameters.filter(function (p) { return p.in === "query"; })[0];
336
+ check("openapi() emits a required path parameter",
337
+ pathParam && pathParam.name === "id" && pathParam.required === true);
338
+ check("openapi() emits the query parameter from queryJsonSchema (required)",
339
+ queryParam && queryParam.name === "q" && queryParam.required === true);
340
+ check("openapi() emits responses from responseJsonSchema",
341
+ getOp.responses && getOp.responses["200"]);
342
+ check("openapi() emits requestBody from bodyJsonSchema",
343
+ doc.paths["/users/{id}"].post.requestBody &&
344
+ doc.paths["/users/{id}"].post.requestBody.required === true);
345
+ check("openapi() annotates a safeSchema-only body with x-blamejs-body-validation",
346
+ doc.paths["/safe"].get["x-blamejs-body-validation"] === "safe-schema (json schema not provided)");
347
+ check("openapi() summarizes a spec-less route from method + pattern",
348
+ doc.paths["/plain"].put.summary === "PUT /plain");
349
+ }
350
+
351
+ function testReservedSlugs() {
352
+ var r = b.router.create();
353
+ r.get("/admin/panel", function () {});
354
+ r.get("/api", function () {});
355
+ r.get("/API/v2", function () {}); // dedupes case-insensitively with /api
356
+ r.get("/:id", function () {}); // param-first: not a reserved slug
357
+ r.get("/", function () {}); // root: no slug
358
+ var slugs = r.getReservedSlugs();
359
+ check("getReservedSlugs collects first literal segments, lowercased + deduped",
360
+ slugs.has("admin") && slugs.has("api") && slugs.size === 2);
361
+ check("getReservedSlugs excludes parameter-first and root patterns",
362
+ !slugs.has(":id") && !slugs.has(""));
363
+ }
364
+
365
+ // ---- ws() registration + lifecycle ----
366
+
367
+ function testWsValidation() {
368
+ check("ws('') refuses empty path",
369
+ /path must be a non-empty string/.test(_throwMsg(function () { b.router.create().ws("", function () {}); })));
370
+ check("ws(path, non-fn) refuses non-function handler",
371
+ /handler must be a function/.test(_throwMsg(function () { b.router.create().ws("/ws", "x"); })));
372
+ check("ws(path, fn, {transport:'h3'}) refuses unknown transport",
373
+ /transport must be/.test(_throwMsg(function () { b.router.create().ws("/ws", function () {}, { transport: "h3" }); })));
374
+ check("ws(path, fn, {origins:'*'}) registers without throwing",
375
+ _throwMsg(function () { b.router.create().ws("/ws", function () {}, { origins: "*" }); }) === null);
376
+ }
377
+
378
+ async function testWebSocketLifecycleCounters() {
379
+ var r = b.router.create();
380
+ check("activeWebSockets() is 0 on a fresh router", r.activeWebSockets() === 0);
381
+ var closed = await r.closeWebSockets();
382
+ check("closeWebSockets() with no open connections resolves to 0", closed === 0);
383
+ }
384
+
385
+ // ---- serveStatic ----
386
+
387
+ async function _runStaticMw(mw, req) {
388
+ var res = _res();
389
+ var nexted = false;
390
+ mw(req, res, function () { nexted = true; });
391
+ // Settle when the middleware finishes — it either called next() (sync or
392
+ // async) or wrote a response. A pass-through that does neither settles as
393
+ // not-nexted once the poll window elapses (waitUntil throws on timeout).
394
+ try {
395
+ await helpers.waitUntil(function () {
396
+ return nexted || res.headersSent || res.writableEnded;
397
+ }, { timeoutMs: 2000, label: "router static mw: next() or response written" });
398
+ } catch (_e) { /* mw neither nexted nor responded — settle as-is */ }
399
+ return { nexted: nexted, res: res };
400
+ }
401
+
402
+ async function testServeStaticBypassBranches() {
403
+ var mw = b.router.serveStatic(os.tmpdir());
404
+ var nonGet = await _runStaticMw(mw, { method: "POST", url: "/x", pathname: "/x", headers: {} });
405
+ check("serveStatic passes non-GET requests through (next)", nonGet.nexted === true);
406
+
407
+ var nul = await _runStaticMw(mw, { method: "GET", url: "/x", pathname: "/xy", headers: {} });
408
+ check("serveStatic passes NUL-byte pathnames through (next)", nul.nexted === true);
409
+
410
+ var traversal = await _runStaticMw(mw, { method: "GET", url: "/x", pathname: "/../../etc/passwd", headers: {} });
411
+ check("serveStatic passes a '..' escape outside root through (next)", traversal.nexted === true);
412
+
413
+ var missing = await _runStaticMw(mw, {
414
+ method: "GET", url: "/x", pathname: "/no-such-file-" + Date.now() + ".html", headers: {},
415
+ });
416
+ check("serveStatic passes a missing file through (next)", missing.nexted === true);
417
+
418
+ // A pathname that resolves to a directory (not a file) is passed through.
419
+ var subdir = fs.mkdtempSync(nodePath.join(os.tmpdir(), "router-dir-"));
420
+ try {
421
+ var dirMw = b.router.serveStatic(os.tmpdir());
422
+ var dirReq = { method: "GET", url: "/x", pathname: "/" + nodePath.basename(subdir), headers: {} };
423
+ var dir = await _runStaticMw(dirMw, dirReq);
424
+ check("serveStatic passes a directory pathname through (next, not a file body)", dir.nexted === true);
425
+ } finally {
426
+ try { fs.rmSync(subdir, { recursive: true, force: true }); } catch (_e) { /* best-effort */ }
427
+ }
428
+ }
429
+
430
+ async function testServeStaticServesFile() {
431
+ var dir = fs.mkdtempSync(nodePath.join(os.tmpdir(), "router-cov-"));
432
+ try {
433
+ fs.writeFileSync(nodePath.join(dir, "hello.html"), "<b>hi</b>");
434
+ fs.writeFileSync(nodePath.join(dir, "blob.xyz"), "rawbytes");
435
+
436
+ var r = b.router.create();
437
+ r.use(b.router.serveStatic(dir));
438
+ var server = r.listen(0);
439
+ await _listening(server);
440
+ var port = server.address().port;
441
+ try {
442
+ var html = await _get(port, "/hello.html");
443
+ check("serveStatic serves a known file with mapped MIME + 1h cache",
444
+ html.status === 200 && html.body === "<b>hi</b>" &&
445
+ html.headers["content-type"] === "text/html" &&
446
+ html.headers["cache-control"] === "public, max-age=3600");
447
+
448
+ var versioned = await _get(port, "/hello.html?v=abc");
449
+ check("serveStatic marks ?v=-versioned URLs immutable for a year",
450
+ versioned.headers["cache-control"] === "public, max-age=31536000, immutable");
451
+
452
+ var blob = await _get(port, "/blob.xyz");
453
+ check("serveStatic falls back to application/octet-stream for unknown extensions",
454
+ blob.status === 200 && blob.headers["content-type"] === "application/octet-stream");
455
+
456
+ var post = await _get(port, "/hello.html", {}, "POST");
457
+ check("serveStatic + no POST route → 404 (non-GET bypass reaches the notFound)",
458
+ post.status === 404);
459
+
460
+ var missing = await _get(port, "/absent.html");
461
+ check("serveStatic + missing file → 404 (bypass reaches the notFound)",
462
+ missing.status === 404);
463
+ } finally {
464
+ await _close(server);
465
+ }
466
+ } finally {
467
+ try { fs.rmSync(dir, { recursive: true, force: true }); } catch (_e) { /* best-effort */ }
468
+ }
469
+ }
470
+
471
+ // ---- live listen() response-helper wiring ----
472
+
473
+ function _listening(server) {
474
+ return new Promise(function (resolve) {
475
+ if (server.listening) { resolve(); return; }
476
+ server.once("listening", resolve);
477
+ });
478
+ }
479
+ function _close(server) { return new Promise(function (resolve) { server.close(resolve); }); }
480
+ function _get(port, path, headers, method) {
481
+ return new Promise(function (resolve, reject) {
482
+ var req = http.request({ host: "127.0.0.1", port: port, path: path, method: method || "GET", headers: headers || {} },
483
+ function (r) {
484
+ var body = "";
485
+ r.on("data", function (c) { body += c; });
486
+ r.on("end", function () { resolve({ status: r.statusCode, headers: r.headers, body: body }); });
487
+ });
488
+ req.on("error", reject);
489
+ req.end();
490
+ });
491
+ }
492
+
493
+ async function testListenResponseHelpers() {
494
+ var r = b.router.create({ allowedRedirectOrigins: ["https://idp.example.com"] });
495
+ r.get("/json", function (req, res) { res.json({ hello: "world" }); });
496
+ r.get("/created", function (req, res) { res.status(201).json({ id: 1 }); });
497
+ r.get("/same", function (req, res) { res.redirect("/dashboard"); });
498
+ r.get("/xo", function (req, res) { res.redirect("https://idp.example.com/authorize?x=1"); });
499
+ r.get("/xo-bad", function (req, res) { try { res.redirect("https://evil.example.com/x"); } catch (e) { res.writeHead(400); res.end("refused:" + e.code); } });
500
+ r.get("/crlf", function (req, res) { try { res.redirect("/a\nEvil:1"); } catch (e) { res.writeHead(400); res.end("refused:" + e.code); } });
501
+ r.get("/boom", function (req, res) { throw new Error("kaboom"); });
502
+ r.onError(function (err, req, res) { res.writeHead(500, { "Content-Type": "text/plain" }); res.end("custom-500:" + err.message); });
503
+
504
+ var server = r.listen(0);
505
+ await _listening(server);
506
+ var port = server.address().port;
507
+ try {
508
+ var j = await _get(port, "/json");
509
+ check("res.json ships 200 + application/json + serialized body",
510
+ j.status === 200 && /application\/json/.test(j.headers["content-type"]) &&
511
+ j.body === '{"hello":"world"}');
512
+
513
+ var created = await _get(port, "/created");
514
+ check("res.status(201).json chains the status through", created.status === 201);
515
+
516
+ var same = await _get(port, "/same");
517
+ check("res.redirect same-origin path → 302 Location", same.status === 302 && same.headers.location === "/dashboard");
518
+
519
+ var xo = await _get(port, "/xo");
520
+ check("res.redirect to an allowlisted cross-origin → 302 Location",
521
+ xo.status === 302 && xo.headers.location === "https://idp.example.com/authorize?x=1");
522
+
523
+ var xoBad = await _get(port, "/xo-bad");
524
+ check("res.redirect to an off-allowlist origin throws RouterError (handler-observable)",
525
+ xoBad.status === 400 && xoBad.body === "refused:router/redirect-cross-origin-refused");
526
+
527
+ var crlf = await _get(port, "/crlf");
528
+ check("res.redirect refuses a LF in the target (header-injection guard)",
529
+ crlf.status === 400 && crlf.body === "refused:router/redirect-target-has-control-chars");
530
+
531
+ var boom = await _get(port, "/boom");
532
+ check("a throwing handler routes through onError to a custom 500",
533
+ boom.status === 500 && boom.body === "custom-500:kaboom");
534
+
535
+ var nf = await _get(port, "/missing");
536
+ check("unmatched path on the live server → 404", nf.status === 404);
537
+ } finally {
538
+ await _close(server);
539
+ }
540
+ }
541
+
542
+ async function testListenDefault500NoErrorHandler() {
543
+ var r = b.router.create();
544
+ r.get("/boom", function () { throw new Error("nope"); });
545
+ var server = r.listen(0);
546
+ await _listening(server);
547
+ var port = server.address().port;
548
+ try {
549
+ var boom = await _get(port, "/boom");
550
+ check("a throwing handler with no onError → default 500 Internal Server Error",
551
+ boom.status === 500 && /Internal Server Error/.test(boom.body));
552
+ } finally {
553
+ await _close(server);
554
+ }
555
+ }
556
+
557
+ async function testListenEarlyDataGate() {
558
+ var r = b.router.create({ tls0Rtt: "refuse" });
559
+ r.get("/e", function (req, res) { res.json({ ok: 1 }); });
560
+ var server = r.listen(0);
561
+ await _listening(server);
562
+ var port = server.address().port;
563
+ try {
564
+ var early = await _get(port, "/e", { "early-data": "1" });
565
+ check("refuse posture: an Early-Data:1 request is gated with 425 at listen()",
566
+ early.status === 425 && early.body === "early-data-refused");
567
+ var normal = await _get(port, "/e");
568
+ check("refuse posture: a normal (non-early-data) request proceeds",
569
+ normal.status === 200);
570
+ } finally {
571
+ await _close(server);
572
+ }
573
+ }
574
+
575
+ // ---- constructor option validation (create opts) ----
576
+
577
+ function testConstructorOptionValidation() {
578
+ check("create({ tls0Rtt: 'bogus' }) throws TypeError naming the valid postures",
579
+ /tls0Rtt must be one of/.test(_throwMsg(function () { b.router.create({ tls0Rtt: "bogus" }); })));
580
+ check("create({ tls0Rtt: 42 }) (non-string) throws TypeError",
581
+ /tls0Rtt must be one of/.test(_throwMsg(function () { b.router.create({ tls0Rtt: 42 }); })));
582
+
583
+ check("create({ allowedRedirectOrigins: 'x' }) (non-array) refuses",
584
+ /allowedRedirectOrigins must be an array/.test(_throwMsg(function () {
585
+ b.router.create({ allowedRedirectOrigins: "https://x.example.com" });
586
+ })));
587
+ check("allowedRedirectOrigins with a non-string entry refuses (index-pointing)",
588
+ /allowedRedirectOrigins\[0\] must be a non-empty string/.test(_throwMsg(function () {
589
+ b.router.create({ allowedRedirectOrigins: [123] });
590
+ })));
591
+ check("allowedRedirectOrigins with an empty-string entry refuses",
592
+ /allowedRedirectOrigins\[0\] must be a non-empty string/.test(_throwMsg(function () {
593
+ b.router.create({ allowedRedirectOrigins: [""] });
594
+ })));
595
+ check("allowedRedirectOrigins with a non-HTTPS origin refuses",
596
+ /is not a valid HTTPS origin/.test(_throwMsg(function () {
597
+ b.router.create({ allowedRedirectOrigins: ["http://plain.example.com"] });
598
+ })));
599
+ check("allowedRedirectOrigins carrying a path refuses (origin form only)",
600
+ /must be an origin/.test(_throwMsg(function () {
601
+ b.router.create({ allowedRedirectOrigins: ["https://idp.example.com/authorize"] });
602
+ })));
603
+ check("allowedRedirectOrigins carrying a query string refuses (origin form only)",
604
+ /must be an origin/.test(_throwMsg(function () {
605
+ b.router.create({ allowedRedirectOrigins: ["https://idp.example.com?next=/x"] });
606
+ })));
607
+ check("allowedRedirectOrigins carrying userinfo refuses (credential-leak guard)",
608
+ /is not a valid HTTPS origin/.test(_throwMsg(function () {
609
+ b.router.create({ allowedRedirectOrigins: ["https://user:pass@idp.example.com"] });
610
+ })));
611
+
612
+ var r = b.router.create({ allowedRedirectOrigins: ["https://idp.example.com"] });
613
+ var copy = r.allowedRedirectOrigins();
614
+ check("allowedRedirectOrigins() reads back the normalized origin",
615
+ copy.length === 1 && copy[0] === "https://idp.example.com");
616
+ copy.push("https://mutated.example.com");
617
+ check("allowedRedirectOrigins() returns a defensive copy (caller mutation does not leak)",
618
+ r.allowedRedirectOrigins().length === 1);
619
+ }
620
+
621
+ // ---- patch / delete verbs ----
622
+
623
+ async function testPatchAndDeleteVerbs() {
624
+ var r = b.router.create();
625
+ var hit = [];
626
+ r.patch("/thing/:id", function (req, res) { hit.push("PATCH:" + req.params.id); res.writeHead(200); res.end("p"); });
627
+ r.delete("/thing/:id", function (req, res) { hit.push("DELETE:" + req.params.id); res.writeHead(200); res.end("d"); });
628
+
629
+ var pres = _res();
630
+ await r.handle(_req("PATCH", "/thing/7"), pres);
631
+ check("router.patch registers + dispatches (PATCH verb)", pres.statusCode === 200 && hit[0] === "PATCH:7");
632
+
633
+ var dres = _res();
634
+ await r.handle(_req("DELETE", "/thing/9"), dres);
635
+ check("router.delete registers + dispatches (DELETE verb)", dres.statusCode === 200 && hit[1] === "DELETE:9");
636
+ }
637
+
638
+ // ---- handle(): adversarial path canonicalization ----
639
+
640
+ async function testHandleEncodedSeparatorRefusals() {
641
+ var r = b.router.create();
642
+ r.get("/a/b", function (req, res) { res.writeHead(200); res.end("ok"); });
643
+
644
+ var enc = _res();
645
+ await r.handle(_req("GET", "/a%2Fb"), enc);
646
+ check("encoded '/' (%2F) in the path → 400 (guard/consumer decoding agreement)",
647
+ enc.statusCode === 400 && /encoded path separator/.test(enc._body));
648
+
649
+ var back = _res();
650
+ await r.handle(_req("GET", "/a%5Cb"), back);
651
+ check("encoded '\\' (%5C) in the path → 400", back.statusCode === 400 && /encoded path separator/.test(back._body));
652
+
653
+ var nul = _res();
654
+ await r.handle(_req("GET", "/a%00b"), nul);
655
+ check("encoded NUL (%00) in the path → 400", nul.statusCode === 400 && /null byte/.test(nul._body));
656
+
657
+ var mal = _res();
658
+ await r.handle(_req("GET", "/a/%zz"), mal);
659
+ check("malformed percent-encoding (%zz) → 400 malformed (decode throws, caught)",
660
+ mal.statusCode === 400 && /malformed percent-encoding/.test(mal._body));
661
+
662
+ var segMismatch = _res();
663
+ await r.handle(_req("GET", "/a/b/c"), segMismatch);
664
+ check("a longer path than the pattern is a no-match (segment-count mismatch) → 404",
665
+ segMismatch.statusCode === 404);
666
+
667
+ // A request with no Host header falls back to the "localhost" base for URL parsing.
668
+ var noHost = _res();
669
+ await r.handle({ method: "GET", url: "/a/b", headers: {} }, noHost);
670
+ check("a request with no Host header resolves against the localhost base (still routes)",
671
+ noHost.statusCode === 200);
672
+ }
673
+
674
+ // ---- path-scoped middleware (use(prefix, mw)) ----
675
+
676
+ async function testPathScopedMiddleware() {
677
+ var r = b.router.create();
678
+ var ran = [];
679
+ r.use("/admin", function adminGate(req, res, next) { ran.push("gate"); next(); });
680
+ r.use(["/api", "/v2"], function apiTag(req, res, next) { ran.push("apitag"); next(); });
681
+ r.get("/admin/panel", function (req, res) { res.writeHead(200); res.end("admin"); });
682
+ r.get("/api/thing", function (req, res) { res.writeHead(200); res.end("api"); });
683
+ r.get("/public", function (req, res) { res.writeHead(200); res.end("public"); });
684
+
685
+ ran = [];
686
+ var a = _res();
687
+ await r.handle(_req("GET", "/admin/panel"), a);
688
+ check("scoped mw under '/admin' runs on '/admin/panel'", a.statusCode === 200 && ran.indexOf("gate") !== -1);
689
+
690
+ ran = [];
691
+ var api = _res();
692
+ await r.handle(_req("GET", "/api/thing"), api);
693
+ check("array-prefix mw ['/api','/v2'] runs when the path matches one prefix",
694
+ api.statusCode === 200 && ran.indexOf("apitag") !== -1);
695
+
696
+ ran = [];
697
+ var pub = _res();
698
+ await r.handle(_req("GET", "/public"), pub);
699
+ check("scoped mw is SKIPPED off-prefix but does NOT short-circuit dispatch",
700
+ pub.statusCode === 200 && pub._body === "public" && ran.length === 0);
701
+
702
+ ran = [];
703
+ var sib = _res();
704
+ r.use("/adm", function () {}); // ensure a substring-prefix does not leak
705
+ await r.handle(_req("GET", "/administrator"), sib);
706
+ check("a scoped prefix matches on segment boundaries, not textual prefix ('/adm' ⊄ '/administrator')",
707
+ ran.length === 0);
708
+
709
+ // A trailing-slash prefix normalizes to the same mount as its slashless form.
710
+ var r2 = b.router.create();
711
+ var teamRan = false;
712
+ r2.use("/team/", function (req, res, next) { teamRan = true; next(); });
713
+ r2.get("/team/roster", function (req, res) { res.writeHead(200); res.end("roster"); });
714
+ var team = _res();
715
+ await r2.handle(_req("GET", "/team/roster"), team);
716
+ check("a trailing-slash mount prefix ('/team/') matches '/team/roster' (normalized)",
717
+ team.statusCode === 200 && teamRan === true);
718
+ }
719
+
720
+ function testUseValidationErrors() {
721
+ check("use() with no args refuses",
722
+ /requires at least one middleware/.test(_throwMsg(function () { b.router.create().use(); })));
723
+ check("use(number) (bad first arg) refuses",
724
+ /first argument must be a middleware/.test(_throwMsg(function () { b.router.create().use(42); })));
725
+ check("use(null) (bad first arg) refuses naming the type",
726
+ /got null/.test(_throwMsg(function () { b.router.create().use(null); })));
727
+ check("use([]) (empty prefix array) refuses",
728
+ /at least one prefix string/.test(_throwMsg(function () { b.router.create().use([], function () {}); })));
729
+ check("use([123], mw) (non-string prefix entry) refuses",
730
+ _throwMsg(function () { b.router.create().use([123], function () {}); }) !== null);
731
+ check("use('admin', mw) (prefix not absolute) refuses",
732
+ /must begin with '\/'/.test(_throwMsg(function () { b.router.create().use("admin", function () {}); })));
733
+ check("use(<over-length prefix>, mw) refuses",
734
+ /exceeds 1024 chars/.test(_throwMsg(function () { b.router.create().use("/" + "a".repeat(1030), function () {}); })));
735
+ check("use('/admin') with no middleware after the prefix refuses",
736
+ /requires at least one middleware/.test(_throwMsg(function () { b.router.create().use("/admin"); })));
737
+ check("use('/admin', notFn) (scoped middleware not a function) refuses (position-pointing)",
738
+ /middleware at position 0 must be a function/.test(_throwMsg(function () { b.router.create().use("/admin", "nope"); })));
739
+ check("use(fn, notFn) (global middleware not a function) refuses",
740
+ /middleware at position 1 must be a function/.test(_throwMsg(function () { b.router.create().use(function () {}, 5); })));
741
+ }
742
+
743
+ // ---- middleware error propagation + mid-chain short-circuit ----
744
+
745
+ async function testMiddlewareErrorRethrows() {
746
+ var r = b.router.create();
747
+ r.use(function boom(req, res, next) { throw new Error("mw-explode"); });
748
+ r.get("/x", function (req, res) { res.writeHead(200); res.end("ok"); });
749
+ var res = _res();
750
+ var threw = null;
751
+ try { await r.handle(_req("GET", "/x"), res); } catch (e) { threw = e; }
752
+ check("a throwing global middleware rejects handle() (error surfaces, not swallowed)",
753
+ threw && /mw-explode/.test(threw.message));
754
+ }
755
+
756
+ async function testWritableEndedBetweenHandlers() {
757
+ var r = b.router.create();
758
+ var ran = [];
759
+ r.get("/two",
760
+ function first(req, res) { ran.push("first"); res.writeHead(200); res.end("first-ends"); },
761
+ function second(req, res) { ran.push("second"); res.writeHead(200); res.end("second"); });
762
+ var res = _res();
763
+ await r.handle(_req("GET", "/two"), res);
764
+ check("once a terminal handler ends the response, the next handler is skipped (writableEnded guard)",
765
+ ran.join(",") === "first" && res._body === "first-ends");
766
+ }
767
+
768
+ // ---- body schema validation + validation-error body sealing ----
769
+
770
+ async function testBodySchemaValidation() {
771
+ var r = b.router.create();
772
+ var handlerRan = false;
773
+ r.post("/create", { body: s.object({ name: s.string() }) }, function (req, res) {
774
+ handlerRan = true; res.writeHead(201); res.end("made:" + req.body.name);
775
+ });
776
+
777
+ var bad = _res();
778
+ await r.handle(_req("POST", "/create"), bad); // no req.body → required body missing
779
+ check("a required body schema with no parsed body → 400 where:body",
780
+ bad.statusCode === 400 && /"where":"body"/.test(bad._body) && handlerRan === false);
781
+
782
+ var okReq = _req("POST", "/create");
783
+ okReq.body = { name: "alice" }; // simulate an upstream body parser
784
+ var ok = _res();
785
+ await r.handle(okReq, ok);
786
+ check("a valid parsed body passes the schema and the handler sees the coerced value",
787
+ ok.statusCode === 201 && ok._body === "made:alice" && handlerRan === true);
788
+ }
789
+
790
+ async function testValidationErrorSealedBody() {
791
+ var r = b.router.create();
792
+ r.post("/sealed", { body: s.object({ name: s.string() }) }, function (req, res) { res.writeHead(201); res.end("ok"); });
793
+
794
+ var sealReq = _req("POST", "/sealed");
795
+ sealReq.apiEncryptEncode = function (payload) { return { sealed: true, where: payload.where }; };
796
+ var sealed = _res();
797
+ await r.handle(sealReq, sealed);
798
+ check("validation error body is sealed through req.apiEncryptEncode when an encrypted session is active",
799
+ sealed.statusCode === 400 && sealed._body === '{"sealed":true,"where":"body"}');
800
+
801
+ var throwReq = _req("POST", "/sealed");
802
+ throwReq.apiEncryptEncode = function () { throw new Error("encoder-down"); };
803
+ var fallback = _res();
804
+ await r.handle(throwReq, fallback);
805
+ check("an encoder that throws falls back to the plaintext validation body (no crash)",
806
+ fallback.statusCode === 400 && /"where":"body"/.test(fallback._body));
807
+ }
808
+
809
+ // ---- response validation: warn mode, raw res.end path, non-JSON skip ----
810
+
811
+ async function testResponseValidatorWarnAndRawEnd() {
812
+ // warn mode via res.json — drift is logged, response ships as-is (200).
813
+ var r1 = b.router.create();
814
+ r1.get("/warn", { response: s.object({ ok: s.boolean() }), validateResponse: "warn" },
815
+ function (req, res) { res.json({ ok: "not-a-boolean" }); });
816
+ var w = _res();
817
+ w.json = function (v) { w.writeHead(200); w.end(JSON.stringify(v)); };
818
+ await r1.handle(_req("GET", "/warn"), w);
819
+ check("response-validation warn mode ships the drifting body as-is (200, no throw)",
820
+ w.statusCode === 200 && /not-a-boolean/.test(w._body));
821
+
822
+ // raw res.end(JSON.stringify(...)) path — the res.end wrapper parses the
823
+ // JSON-shaped buffer and validates it even without res.json.
824
+ var r2 = b.router.create();
825
+ r2.get("/raw", { response: s.object({ ok: s.boolean() }), validateResponse: "warn" },
826
+ function (req, res2) { res2.writeHead(200); res2.end(JSON.stringify({ ok: "drift" })); });
827
+ var raw = _res();
828
+ await r2.handle(_req("GET", "/raw"), raw);
829
+ check("a raw res.end(JSON) body is validated by the res.end wrapper (warn, ships)",
830
+ raw.statusCode === 200 && /drift/.test(raw._body));
831
+
832
+ // non-JSON body is skipped by _bodyLooksLikeJson (leading '<').
833
+ var r3 = b.router.create();
834
+ r3.get("/html", { response: s.object({ ok: s.boolean() }), validateResponse: "warn" },
835
+ function (req, res3) { res3.writeHead(200); res3.end("<h1>not json</h1>"); });
836
+ var htmlRes = _res();
837
+ await r3.handle(_req("GET", "/html"), htmlRes);
838
+ check("a non-JSON (HTML) response body is skipped by the response validator (no parse attempt)",
839
+ htmlRes.statusCode === 200 && htmlRes._body === "<h1>not json</h1>");
840
+
841
+ // whitespace-leading JSON is still recognized + validated (warn, ships).
842
+ var r4 = b.router.create();
843
+ r4.get("/ws", { response: s.object({ ok: s.boolean() }), validateResponse: "warn" },
844
+ function (req, res4) { res4.writeHead(200); res4.end(" {\"ok\":\"drift\"}"); });
845
+ var wsRes = _res();
846
+ await r4.handle(_req("GET", "/ws"), wsRes);
847
+ check("a whitespace-leading JSON body is recognized + validated by the res.end wrapper",
848
+ wsRes.statusCode === 200 && /drift/.test(wsRes._body));
849
+
850
+ // a Buffer body that looks like JSON is decoded + validated by the wrapper.
851
+ var r4b = b.router.create();
852
+ r4b.get("/buf", { response: s.object({ ok: s.boolean() }), validateResponse: "warn" },
853
+ function (req, res4b) { res4b.writeHead(200); res4b.end(Buffer.from("{\"ok\":\"drift\"}")); });
854
+ var bufRes = _res();
855
+ await r4b.handle(_req("GET", "/buf"), bufRes);
856
+ check("a Buffer response body that looks like JSON is decoded + validated (warn, ships)",
857
+ bufRes.statusCode === 200 && /drift/.test(bufRes._body));
858
+
859
+ // a JSON-shaped-but-unparseable body is skipped (parse throws, caught).
860
+ var r4c = b.router.create();
861
+ r4c.get("/broken", { response: s.object({ ok: s.boolean() }), validateResponse: "throw" },
862
+ function (req, res4c) { res4c.writeHead(200); res4c.end("{not valid json"); });
863
+ var brokenRes = _res();
864
+ var brokenThrew = null;
865
+ try { await r4c.handle(_req("GET", "/broken"), brokenRes); } catch (e) { brokenThrew = e; }
866
+ check("a JSON-shaped but unparseable body is skipped by the validator (no crash, ships)",
867
+ brokenThrew === null && brokenRes.statusCode === 200 && brokenRes._body === "{not valid json");
868
+
869
+ // an all-whitespace body is not treated as JSON (loop completes, returns false).
870
+ var r4d = b.router.create();
871
+ r4d.get("/blank", { response: s.object({ ok: s.boolean() }), validateResponse: "throw" },
872
+ function (req, res4d) { res4d.writeHead(200); res4d.end(" "); });
873
+ var blankRes = _res();
874
+ var blankThrew = null;
875
+ try { await r4d.handle(_req("GET", "/blank"), blankRes); } catch (e) { blankThrew = e; }
876
+ check("an all-whitespace response body is not mistaken for JSON (no validation attempt)",
877
+ blankThrew === null && blankRes.statusCode === 200);
878
+
879
+ // throw mode, but headers already sent on a raw res.end — degrades to a
880
+ // logged error (cannot un-send), still ships.
881
+ var r5 = b.router.create();
882
+ r5.get("/late", { response: s.object({ ok: s.boolean() }), validateResponse: "throw" },
883
+ function (req, res5) { res5.writeHead(200); res5.end(JSON.stringify({ ok: "drift" })); });
884
+ var late = _res();
885
+ var threw = null;
886
+ try { await r5.handle(_req("GET", "/late"), late); } catch (e) { threw = e; }
887
+ check("throw mode after headers already sent degrades to a logged error (no mid-flush throw)",
888
+ threw === null && late.statusCode === 200 && /drift/.test(late._body));
889
+
890
+ // validateResponse truthy-but-not-throw/warn → validator installed but
891
+ // passthrough (no active mode).
892
+ var r6 = b.router.create();
893
+ var ranPass = false;
894
+ r6.get("/pass", { response: s.object({ ok: s.boolean() }), validateResponse: true },
895
+ function (req, res6) { ranPass = true; res6.writeHead(200); res6.end(JSON.stringify({ ok: "anything" })); });
896
+ var pass = _res();
897
+ await r6.handle(_req("GET", "/pass"), pass);
898
+ check("validateResponse truthy-but-not-'throw'/'warn' installs a passthrough (no validation)",
899
+ ranPass === true && pass.statusCode === 200);
900
+ }
901
+
902
+ // ---- TLS 1.3 0-RTT anti-replay (direct _check0RttReplay drive) ----
903
+
904
+ function test0RttReplayCacheDirect() {
905
+ var refuse = b.router.create({ tls0Rtt: "refuse" });
906
+ check("refuse posture: a non-early-data request is allowed through (null verdict)",
907
+ refuse._check0RttReplay(helpers._mockReq({ method: "GET", url: "/x" })) === null);
908
+ var refuseVerdict = refuse._check0RttReplay(helpers._mockReq({ method: "POST", url: "/charge", headers: { "early-data": "1" } }));
909
+ check("refuse posture: an Early-Data:1 request is refused 425",
910
+ refuseVerdict && refuseVerdict.status === 425 && refuseVerdict.reason === "early-data-refused");
911
+
912
+ var replay = b.router.create({ tls0Rtt: "replay-cache" });
913
+ var hdrs = { "early-data": "1", host: "api.example.com", authorization: "Bearer t", date: "Fri, 01 Jan 2027 00:00:00 GMT" };
914
+ var first = replay._check0RttReplay(helpers._mockReq({ method: "POST", url: "/charge", headers: hdrs }));
915
+ check("replay-cache: the first Early-Data:1 request is admitted (cached)", first === null);
916
+ var second = replay._check0RttReplay(helpers._mockReq({ method: "POST", url: "/charge", headers: Object.assign({}, hdrs) }));
917
+ check("replay-cache: an identical Early-Data:1 replay is refused 425 (cache hit)",
918
+ second && second.status === 425 && second.reason === "early-data-replay");
919
+ var distinct = replay._check0RttReplay(helpers._mockReq({ method: "POST", url: "/charge",
920
+ headers: Object.assign({}, hdrs, { "idempotency-key": "k-2" }) }));
921
+ check("replay-cache: a distinct (idempotency-keyed) request is admitted",
922
+ distinct === null);
923
+ // Early-Data header present but not "1" (RFC 8470: only "1" is early data).
924
+ check("replay-cache: Early-Data header != '1' is treated as a normal request",
925
+ replay._check0RttReplay(helpers._mockReq({ method: "GET", url: "/x", headers: { "early-data": "0" } })) === null);
926
+ }
927
+
928
+ function test0RttReplayCacheEviction() {
929
+ var replay = b.router.create({ tls0Rtt: "replay-cache" });
930
+ // Insert past the bounded entry cap (4096) with distinct early-data
931
+ // requests so the oldest entries are evicted to make room.
932
+ var cap = 4096;
933
+ for (var i = 0; i < cap + 32; i += 1) {
934
+ var v = replay._check0RttReplay(helpers._mockReq({
935
+ method: "POST", url: "/charge",
936
+ headers: { "early-data": "1", "idempotency-key": "evict-" + i },
937
+ }));
938
+ if (v !== null) { check("replay-cache eviction: every distinct request is admitted", false); return; }
939
+ }
940
+ check("replay-cache eviction: distinct-request insertions past the 4096 cap all admit", true);
941
+ check("replay-cache eviction: the cache stays bounded at the entry cap",
942
+ replay._tls0RttReplayCache.size === cap);
943
+ }
944
+
945
+ function test0RttFailClosedUnderPci() {
946
+ var prior = null;
947
+ try { prior = compliance.current ? compliance.current() : null; } catch (_e) { /* not set */ }
948
+ if (prior) {
949
+ // Posture already pinned in this process — reset so the assertion is deterministic.
950
+ try { compliance._resetForTest(); } catch (_e) { /* best-effort */ }
951
+ }
952
+ try {
953
+ compliance.set("pci-dss");
954
+ var r = b.router.create({ tls0Rtt: "replay-cache" });
955
+ check("replay-cache fail-closes to 'refuse' under the pci-dss posture (RFC 8446 §8 / PCI 6.4.3)",
956
+ r._effective0RttPosture() === "refuse");
957
+ } finally {
958
+ try { compliance._resetForTest(); } catch (_e) { /* best-effort */ }
959
+ }
960
+ }
961
+
962
+ // ---- listen(): TLS server setup path (config branches, no handshake) ----
963
+
964
+ async function _makeServerCert() {
965
+ var ca = await mtlsEngine.generateCa({ name: "routertestca" });
966
+ var leaf = await mtlsEngine.signClientCert({
967
+ cn: "localhost", usage: "server", caCertPem: ca.caCertPem, caKeyPem: ca.caKeyPem,
968
+ });
969
+ return { key: leaf.key, cert: leaf.cert };
970
+ }
971
+
972
+ async function testTlsListenSetup() {
973
+ var cert = await _makeServerCert();
974
+
975
+ // Variant 1 — bare {key, cert} + operator SNICallback. Exercises the
976
+ // SNICallback wrapper install, the TLS 1.3 minVersion default, and the
977
+ // posture-driven allowEarlyData default.
978
+ var r1 = b.router.create({ tls0Rtt: "refuse" });
979
+ r1.get("/e", function (req, res) { res.json({ ok: 1 }); });
980
+ var s1 = r1.listen(0, function () {}, {
981
+ key: cert.key, cert: cert.cert,
982
+ // Present so the framework wraps it (CVE-2026-21637); the body only
983
+ // runs on a handshake, which testTlsH2Handshake drives.
984
+ SNICallback: function (servername, cb) { cb(null, null); },
985
+ });
986
+ try {
987
+ await _listening(s1);
988
+ check("listen() with tlsOptions boots an HTTP/2-capable TLS server (ALPN h2 + http/1.1)",
989
+ s1.listening === true && typeof s1.address().port === "number");
990
+ check("TLS server pins the Slowloris header/keepalive timeouts",
991
+ s1.headersTimeout === 60000 && s1.keepAliveTimeout === 5000);
992
+ } finally {
993
+ await _close(s1);
994
+ }
995
+
996
+ // Variant 2 — operator-supplied minVersion + allowEarlyData + no
997
+ // SNICallback, under the replay-cache posture. Exercises the
998
+ // "already-set, skip the default" branches.
999
+ var r2 = b.router.create({ tls0Rtt: "replay-cache" });
1000
+ r2.get("/e", function (req, res) { res.json({ ok: 1 }); });
1001
+ var s2 = r2.listen(0, function () {}, {
1002
+ key: cert.key, cert: cert.cert, minVersion: "TLSv1.3", allowEarlyData: false,
1003
+ });
1004
+ try {
1005
+ await _listening(s2);
1006
+ check("listen() honors operator-supplied minVersion + allowEarlyData (no default override)",
1007
+ s2.listening === true);
1008
+ } finally {
1009
+ await _close(s2);
1010
+ }
1011
+ }
1012
+
1013
+ // A classical (ECDSA P-256) self-signed leaf so a real TLS 1.3 h2
1014
+ // handshake completes in-process — the mtls engine issues ML-DSA certs,
1015
+ // which node:tls cannot yet negotiate, so the vendored x509 generator is
1016
+ // driven directly here for a handshake-capable server cert.
1017
+ async function _makeClassicalServerCert() {
1018
+ var x509 = pki.x509;
1019
+ var webcrypto = pki.crypto;
1020
+ var keys = await webcrypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]);
1021
+ var cert = await x509.X509CertificateGenerator.createSelfSigned({
1022
+ serialNumber: "01",
1023
+ name: "CN=localhost",
1024
+ notBefore: new Date(Date.now() - C.TIME.hours(1)),
1025
+ notAfter: new Date(Date.now() + C.TIME.hours(1)),
1026
+ signingAlgorithm: { name: "ECDSA", hash: "SHA-256" },
1027
+ keys: keys,
1028
+ extensions: [new x509.SubjectAlternativeNameExtension([{ type: "dns", value: "localhost" }])],
1029
+ });
1030
+ var pkcs8 = await webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
1031
+ var keyPem = "-----BEGIN PRIVATE KEY-----\n" +
1032
+ Buffer.from(pkcs8).toString("base64").replace(/(.{64})/g, "$1\n") +
1033
+ "\n-----END PRIVATE KEY-----\n";
1034
+ return { key: keyPem, cert: cert.toString("pem") };
1035
+ }
1036
+
1037
+ async function testTlsH2Handshake() {
1038
+ var cert = await _makeClassicalServerCert();
1039
+ var r = b.router.create({ tls0Rtt: "refuse" });
1040
+ r.get("/e", function (req, res) { res.json({ ok: 1 }); });
1041
+ var sniSeen = false;
1042
+ var capturedSession = null;
1043
+ var server = r.listen(0, function () {}, {
1044
+ key: cert.key, cert: cert.cert,
1045
+ SNICallback: function (servername, cb) { sniSeen = true; cb(null, null); },
1046
+ });
1047
+ server.on("session", function (sess) { if (!capturedSession) capturedSession = sess; });
1048
+ await _listening(server);
1049
+ var port = server.address().port;
1050
+ var client = null;
1051
+ try {
1052
+ client = http2.connect("https://localhost:" + port, { ca: cert.cert, servername: "localhost" });
1053
+ var got = await new Promise(function (resolve) {
1054
+ client.on("error", function (e) { resolve({ err: e.message }); });
1055
+ var creq = client.request({ ":path": "/e" });
1056
+ var body = "", st = null;
1057
+ creq.on("response", function (h) { st = h[":status"]; });
1058
+ creq.on("data", function (d) { body += d; });
1059
+ creq.on("end", function () { resolve({ status: st, body: body }); });
1060
+ creq.on("error", function (e) { resolve({ err: e.message }); });
1061
+ creq.end();
1062
+ });
1063
+ check("a real TLS 1.3 h2 handshake + GET returns the handler's JSON (200)",
1064
+ got.status === 200 && got.body === '{"ok":1}');
1065
+ check("the operator SNICallback is invoked (framework wraps it against synchronous throws)",
1066
+ sniSeen === true);
1067
+ check("the framework registers a per-session GOAWAY guard (CVE-2026-21714)",
1068
+ capturedSession !== null && capturedSession._blamejsGoawaySent === false);
1069
+
1070
+ // Drive the framework's wrapped goaway() so the guard flips the
1071
+ // session's GOAWAY flag (defense-in-depth WINDOW_UPDATE-after-GOAWAY).
1072
+ if (capturedSession && typeof capturedSession.goaway === "function") {
1073
+ capturedSession.goaway();
1074
+ await helpers.waitUntil(function () { return capturedSession._blamejsGoawaySent === true; },
1075
+ { timeoutMs: 2000, label: "h2: framework goaway wrapper flips the guard flag" });
1076
+ check("the wrapped goaway() marks the session so post-GOAWAY frames are refused",
1077
+ capturedSession._blamejsGoawaySent === true);
1078
+ }
1079
+ } finally {
1080
+ try { if (client) client.close(); } catch (_e) { /* best-effort */ }
1081
+ await _close(server);
1082
+ }
1083
+ }
1084
+
1085
+ async function testTlsSniCallbackThrows() {
1086
+ var cert = await _makeClassicalServerCert();
1087
+ var r = b.router.create();
1088
+ r.get("/e", function (req, res) { res.json({ ok: 1 }); });
1089
+ var operatorSniInvoked = false;
1090
+ // CVE-2026-21637 — a synchronous throw from the operator SNICallback must
1091
+ // not crash the TLS listener; the framework wraps it into a clean
1092
+ // (err, null) callback and aborts just that handshake.
1093
+ var server = r.listen(0, function () {}, {
1094
+ key: cert.key, cert: cert.cert,
1095
+ SNICallback: function (servername, cb) { operatorSniInvoked = true; throw new Error("sni-boom"); },
1096
+ });
1097
+ await _listening(server);
1098
+ var port = server.address().port;
1099
+ var client = null;
1100
+ try {
1101
+ var clientOutcome = null; // "error" | "connect"
1102
+ client = http2.connect("https://localhost:" + port, { ca: cert.cert, servername: "localhost" });
1103
+ client.on("error", function () { if (clientOutcome === null) clientOutcome = "error"; });
1104
+ client.on("connect", function () { if (clientOutcome === null) clientOutcome = "connect"; });
1105
+ await helpers.waitUntil(function () { return operatorSniInvoked && clientOutcome !== null; },
1106
+ { timeoutMs: 4000, label: "tls: SNICallback invoked + handshake resolved" });
1107
+ check("a throwing operator SNICallback is caught by the framework (listener survives, handshake aborts)",
1108
+ operatorSniInvoked === true && clientOutcome === "error");
1109
+ // The server is still up and can be closed cleanly (no listener crash).
1110
+ check("the TLS listener remains healthy after the SNICallback throw", server.listening === true);
1111
+ } finally {
1112
+ try { if (client) client.destroy(); } catch (_e) { /* best-effort */ }
1113
+ await _close(server);
1114
+ }
1115
+ }
1116
+
1117
+ // ---- listen(): h1 WebSocket upgrade routing ----
1118
+
1119
+ async function _rawUpgrade(port, path, extraHeaders) {
1120
+ var buf = "";
1121
+ var closed = false;
1122
+ var sock = net.connect(port, "127.0.0.1", function () {
1123
+ var key = crypto.randomBytes(16).toString("base64");
1124
+ var lines = [
1125
+ "GET " + path + " HTTP/1.1", "Host: localhost:" + port,
1126
+ "Upgrade: websocket", "Connection: Upgrade",
1127
+ "Sec-WebSocket-Key: " + key, "Sec-WebSocket-Version: 13",
1128
+ ].concat(extraHeaders || []);
1129
+ sock.write(lines.join("\r\n") + "\r\n\r\n");
1130
+ });
1131
+ sock.on("data", function (d) { buf += d.toString("latin1"); });
1132
+ sock.on("close", function () { closed = true; });
1133
+ sock.on("error", function () { closed = true; });
1134
+ // A refuse path destroys the socket (close fires); an accepted 101 keeps
1135
+ // the socket open, so settle once the response headers are fully framed.
1136
+ try {
1137
+ await helpers.waitUntil(function () { return closed || /\r\n\r\n/.test(buf); },
1138
+ { timeoutMs: 4000, label: "router ws h1 upgrade: response framed or socket closed (" + path + ")" });
1139
+ } catch (_e) { /* settle as-is */ }
1140
+ return { buf: buf, sock: sock, closed: closed };
1141
+ }
1142
+
1143
+ async function testWsListenH1Upgrade() {
1144
+ var r = b.router.create();
1145
+ var handlerConn = null;
1146
+ r.ws("/ws", function (conn) { handlerConn = conn; }, { origins: "*" });
1147
+ r.ws("/h2only", function () {}, { origins: "*", transport: "h2-only" });
1148
+ // A route registered WITHOUT origins to drive the startup warn branch.
1149
+ r.ws("/noorigins", function () {}, {});
1150
+
1151
+ var server = r.listen(0);
1152
+ await _listening(server);
1153
+ var port = server.address().port;
1154
+ var okSock = null;
1155
+ try {
1156
+ var unknown = await _rawUpgrade(port, "/not-registered");
1157
+ check("h1 upgrade to an unregistered ws path → socket destroyed (no response)",
1158
+ unknown.closed === true && unknown.buf === "");
1159
+
1160
+ var h2only = await _rawUpgrade(port, "/h2only");
1161
+ check("h1 upgrade to an h2-only ws path → 426 Upgrade Required + 'Upgrade: h2c'",
1162
+ /426 Upgrade Required/.test(h2only.buf) && /Upgrade: h2c/.test(h2only.buf));
1163
+
1164
+ var okUp = await _rawUpgrade(port, "/ws");
1165
+ okSock = okUp.sock;
1166
+ check("a valid h1 ws handshake → 101 Switching Protocols and the handler is invoked",
1167
+ /101 Switching Protocols/.test(okUp.buf) && handlerConn !== null);
1168
+ await helpers.waitUntil(function () { return r.activeWebSockets() === 1; },
1169
+ { timeoutMs: 3000, label: "router ws: upgraded connection tracked" });
1170
+ check("activeWebSockets() reflects the open upgraded connection",
1171
+ r.activeWebSockets() === 1);
1172
+
1173
+ var closedN = await r.closeWebSockets({ timeoutMs: 200 });
1174
+ check("closeWebSockets() closes the live connection and returns the count",
1175
+ closedN === 1);
1176
+ } finally {
1177
+ try { if (okSock) okSock.destroy(); } catch (_e) { /* best-effort */ }
1178
+ await _close(server);
1179
+ }
1180
+ }
1181
+
1182
+ // ---- listen(): redirect + errorHandler edge branches ----
1183
+
1184
+ async function testRedirectAndErrorBranches() {
1185
+ var r = b.router.create(); // no allowedRedirectOrigins → empty allowlist
1186
+ r.get("/r-nonstring", function (req, res) {
1187
+ try { res.redirect(123); } catch (e) { res.writeHead(400); res.end("code:" + e.code); }
1188
+ });
1189
+ r.get("/r-parsefail", function (req, res) {
1190
+ try { res.redirect("http://plain.example.com/x"); } catch (e) { res.writeHead(400); res.end("code:" + e.code); }
1191
+ });
1192
+ r.get("/r-noallowlist", function (req, res) {
1193
+ try { res.redirect("https://valid.example.com/x"); } catch (e) { res.writeHead(400); res.end("code:" + e.code); }
1194
+ });
1195
+ r.get("/boom", function () { throw new Error("handler-down"); });
1196
+ // An error handler that itself throws → the default 500 fallback must still fire.
1197
+ r.onError(function () { throw new Error("errorHandler-down"); });
1198
+
1199
+ var server = r.listen(0);
1200
+ await _listening(server);
1201
+ var port = server.address().port;
1202
+ try {
1203
+ var nonStr = await _get(port, "/r-nonstring");
1204
+ check("res.redirect(non-string) throws router/redirect-target-not-string",
1205
+ nonStr.status === 400 && nonStr.body === "code:router/redirect-target-not-string");
1206
+
1207
+ var parseFail = await _get(port, "/r-parsefail");
1208
+ check("res.redirect to a non-HTTPS cross-origin target is refused (parse rejects http)",
1209
+ parseFail.status === 400 && parseFail.body === "code:router/redirect-cross-origin-refused");
1210
+
1211
+ var noAllow = await _get(port, "/r-noallowlist");
1212
+ check("res.redirect cross-origin with an empty allowlist is refused",
1213
+ noAllow.status === 400 && noAllow.body === "code:router/redirect-cross-origin-refused");
1214
+
1215
+ var boom = await _get(port, "/boom");
1216
+ check("an error handler that itself throws still yields the default 500",
1217
+ boom.status === 500 && /Internal Server Error/.test(boom.body));
1218
+ } finally {
1219
+ await _close(server);
1220
+ }
1221
+ }
1222
+
1223
+ async function run() {
1224
+ testPatternValidation();
1225
+ testAsteriskFloodRefused();
1226
+ testRouteSpecValidation();
1227
+ await testMethodMismatchFallsToNotFound();
1228
+ await testDefaultNotFoundBody();
1229
+ await testCustomNotFound();
1230
+ await testParamCaptureAndRoutePattern();
1231
+ await testTrailingSlashParamNoMatch();
1232
+ await testMultiHandlerFallThrough();
1233
+ await testInRouteMiddlewareNextSemantics();
1234
+ await testGlobalMwEndsResponseWithNextStopsDispatch();
1235
+ await testQueryPopulated();
1236
+ await testQueryKeyCap();
1237
+ await testQuerySchemaValidation();
1238
+ await testParamsSchemaValidation();
1239
+ await testResponseValidatorThrowMode();
1240
+ testInspectRoutes();
1241
+ testOpenapi();
1242
+ testReservedSlugs();
1243
+ testWsValidation();
1244
+ await testWebSocketLifecycleCounters();
1245
+ await testServeStaticBypassBranches();
1246
+ await testServeStaticServesFile();
1247
+ await testListenResponseHelpers();
1248
+ await testListenDefault500NoErrorHandler();
1249
+ await testListenEarlyDataGate();
1250
+ testConstructorOptionValidation();
1251
+ await testPatchAndDeleteVerbs();
1252
+ await testHandleEncodedSeparatorRefusals();
1253
+ await testPathScopedMiddleware();
1254
+ testUseValidationErrors();
1255
+ await testMiddlewareErrorRethrows();
1256
+ await testWritableEndedBetweenHandlers();
1257
+ await testBodySchemaValidation();
1258
+ await testValidationErrorSealedBody();
1259
+ await testResponseValidatorWarnAndRawEnd();
1260
+ test0RttReplayCacheDirect();
1261
+ test0RttReplayCacheEviction();
1262
+ test0RttFailClosedUnderPci();
1263
+ await testTlsListenSetup();
1264
+ await testTlsH2Handshake();
1265
+ await testTlsSniCallbackThrows();
1266
+ await testWsListenH1Upgrade();
1267
+ await testRedirectAndErrorBranches();
1268
+ }
1269
+
1270
+ module.exports = { run: run };
1271
+
1272
+ if (require.main === module) {
1273
+ run().then(
1274
+ function () { console.log("OK router — " + helpers.getChecks() + " checks"); process.exit(0); },
1275
+ function (e) { console.error("FAIL:", (e && e.stack) || e); process.exit(1); }
1276
+ );
1277
+ }