@blamejs/blamejs-shop 0.5.12 → 0.5.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (522) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/sales-tax-filings.js +143 -0
  4. package/lib/vendor/MANIFEST.json +632 -416
  5. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
  6. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
  7. package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
  8. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  9. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
  10. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
  11. package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
  12. package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
  13. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
  14. package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
  15. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
  16. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  17. package/lib/vendor/blamejs/.gitignore +2 -0
  18. package/lib/vendor/blamejs/CHANGELOG.md +122 -0
  19. package/lib/vendor/blamejs/NOTICE +26 -1
  20. package/lib/vendor/blamejs/SECURITY.md +1 -1
  21. package/lib/vendor/blamejs/api-snapshot.json +207 -5
  22. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
  23. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
  24. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
  25. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
  26. package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
  27. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  28. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
  29. package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
  30. package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
  31. package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
  32. package/lib/vendor/blamejs/index.js +6 -0
  33. package/lib/vendor/blamejs/lib/a2a.js +4 -4
  34. package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
  35. package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
  36. package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
  37. package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
  38. package/lib/vendor/blamejs/lib/archive-read.js +8 -0
  39. package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
  40. package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
  41. package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
  42. package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
  43. package/lib/vendor/blamejs/lib/audit.js +71 -8
  44. package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
  45. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
  46. package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
  47. package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
  48. package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
  49. package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
  50. package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
  51. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
  52. package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
  53. package/lib/vendor/blamejs/lib/backup/index.js +16 -5
  54. package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
  55. package/lib/vendor/blamejs/lib/base32.js +21 -0
  56. package/lib/vendor/blamejs/lib/break-glass.js +19 -10
  57. package/lib/vendor/blamejs/lib/bundler.js +5 -1
  58. package/lib/vendor/blamejs/lib/cache-status.js +3 -7
  59. package/lib/vendor/blamejs/lib/calendar.js +21 -1
  60. package/lib/vendor/blamejs/lib/cbor.js +12 -1
  61. package/lib/vendor/blamejs/lib/cert.js +29 -11
  62. package/lib/vendor/blamejs/lib/cli.js +94 -24
  63. package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
  64. package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
  65. package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
  66. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
  67. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
  68. package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
  69. package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
  70. package/lib/vendor/blamejs/lib/content-digest.js +2 -1
  71. package/lib/vendor/blamejs/lib/cookies.js +13 -3
  72. package/lib/vendor/blamejs/lib/cose.js +31 -16
  73. package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
  74. package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
  75. package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
  76. package/lib/vendor/blamejs/lib/crypto.js +314 -19
  77. package/lib/vendor/blamejs/lib/csp.js +11 -3
  78. package/lib/vendor/blamejs/lib/daemon.js +270 -24
  79. package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
  80. package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
  81. package/lib/vendor/blamejs/lib/db-query.js +34 -7
  82. package/lib/vendor/blamejs/lib/db.js +18 -6
  83. package/lib/vendor/blamejs/lib/dbsc.js +17 -0
  84. package/lib/vendor/blamejs/lib/dev.js +21 -2
  85. package/lib/vendor/blamejs/lib/dsr.js +157 -102
  86. package/lib/vendor/blamejs/lib/external-db.js +41 -2
  87. package/lib/vendor/blamejs/lib/file-upload.js +25 -7
  88. package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
  89. package/lib/vendor/blamejs/lib/forms.js +113 -27
  90. package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
  91. package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
  92. package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
  93. package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
  94. package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
  95. package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
  96. package/lib/vendor/blamejs/lib/guard-html.js +26 -53
  97. package/lib/vendor/blamejs/lib/guard-image.js +24 -5
  98. package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
  99. package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
  100. package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
  101. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
  102. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
  103. package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
  104. package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
  105. package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
  106. package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
  107. package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
  108. package/lib/vendor/blamejs/lib/guard-time.js +1 -1
  109. package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
  110. package/lib/vendor/blamejs/lib/html-balance.js +3 -3
  111. package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
  112. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
  113. package/lib/vendor/blamejs/lib/http-client.js +39 -7
  114. package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
  115. package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
  116. package/lib/vendor/blamejs/lib/i18n.js +35 -21
  117. package/lib/vendor/blamejs/lib/incident-report.js +8 -1
  118. package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
  119. package/lib/vendor/blamejs/lib/json-path.js +23 -1
  120. package/lib/vendor/blamejs/lib/jwk.js +20 -3
  121. package/lib/vendor/blamejs/lib/link-header.js +2 -1
  122. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
  123. package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
  124. package/lib/vendor/blamejs/lib/log-stream.js +8 -3
  125. package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
  126. package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
  127. package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
  128. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
  129. package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
  130. package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
  131. package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
  132. package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
  133. package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
  134. package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
  135. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
  136. package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
  137. package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
  138. package/lib/vendor/blamejs/lib/mail.js +15 -5
  139. package/lib/vendor/blamejs/lib/metrics.js +268 -63
  140. package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
  141. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
  142. package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
  143. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
  144. package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
  145. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
  146. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
  147. package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
  148. package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
  149. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
  150. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
  151. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
  152. package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
  153. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
  154. package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
  155. package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
  156. package/lib/vendor/blamejs/lib/network-dns.js +21 -2
  157. package/lib/vendor/blamejs/lib/network-tls.js +69 -7
  158. package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
  159. package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
  160. package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
  161. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
  162. package/lib/vendor/blamejs/lib/outbox.js +1 -1
  163. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
  164. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
  165. package/lib/vendor/blamejs/lib/permissions.js +6 -3
  166. package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
  167. package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
  168. package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
  169. package/lib/vendor/blamejs/lib/pubsub.js +20 -9
  170. package/lib/vendor/blamejs/lib/queue-local.js +8 -1
  171. package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
  172. package/lib/vendor/blamejs/lib/redact.js +54 -0
  173. package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
  174. package/lib/vendor/blamejs/lib/restore.js +19 -0
  175. package/lib/vendor/blamejs/lib/retention.js +12 -4
  176. package/lib/vendor/blamejs/lib/router.js +60 -6
  177. package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
  178. package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
  179. package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
  180. package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
  181. package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
  182. package/lib/vendor/blamejs/lib/safe-object.js +80 -0
  183. package/lib/vendor/blamejs/lib/safe-path.js +52 -4
  184. package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
  185. package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
  186. package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
  187. package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
  188. package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
  189. package/lib/vendor/blamejs/lib/scheduler.js +8 -1
  190. package/lib/vendor/blamejs/lib/security-assert.js +6 -6
  191. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
  192. package/lib/vendor/blamejs/lib/self-update.js +517 -87
  193. package/lib/vendor/blamejs/lib/server-timing.js +2 -4
  194. package/lib/vendor/blamejs/lib/session.js +34 -12
  195. package/lib/vendor/blamejs/lib/sql.js +15 -1
  196. package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
  197. package/lib/vendor/blamejs/lib/static.js +55 -13
  198. package/lib/vendor/blamejs/lib/storage.js +8 -2
  199. package/lib/vendor/blamejs/lib/subject.js +6 -1
  200. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
  201. package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
  202. package/lib/vendor/blamejs/lib/tsa.js +34 -13
  203. package/lib/vendor/blamejs/lib/uri-template.js +8 -1
  204. package/lib/vendor/blamejs/lib/vault/index.js +13 -0
  205. package/lib/vendor/blamejs/lib/vc.js +44 -5
  206. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
  207. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
  208. package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
  209. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
  210. package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
  212. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
  213. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
  214. package/lib/vendor/blamejs/lib/watcher.js +89 -17
  215. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
  216. package/lib/vendor/blamejs/lib/webhook.js +12 -2
  217. package/lib/vendor/blamejs/lib/ws-client.js +32 -1
  218. package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
  219. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
  220. package/lib/vendor/blamejs/package-lock.json +2 -2
  221. package/lib/vendor/blamejs/package.json +1 -1
  222. package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
  223. package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
  224. package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
  225. package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
  226. package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
  227. package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
  228. package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
  229. package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
  230. package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
  231. package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
  232. package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
  233. package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
  234. package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
  235. package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
  236. package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
  237. package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
  238. package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
  239. package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
  240. package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
  241. package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
  242. package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
  243. package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
  244. package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
  245. package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
  246. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
  247. package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
  248. package/lib/vendor/blamejs/socket.yml +94 -0
  249. package/lib/vendor/blamejs/test/00-primitives.js +605 -0
  250. package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
  251. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
  252. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
  253. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
  254. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
  255. package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
  256. package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
  257. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
  258. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
  259. package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
  260. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
  263. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
  269. package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
  271. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
  285. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
  294. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
  295. package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
  303. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
  308. package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
  315. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
  317. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
  318. package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
  319. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
  320. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
  321. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
  322. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
  323. package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
  324. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
  325. package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
  326. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
  327. package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
  328. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
  329. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
  330. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
  331. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
  334. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
  335. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
  336. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
  337. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
  341. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
  342. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
  346. package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
  347. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
  348. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
  349. package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
  365. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
  376. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
  377. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
  388. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
  389. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
  390. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
  391. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
  392. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
  393. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
  395. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
  396. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
  397. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
  398. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
  399. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
  400. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
  401. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
  402. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
  403. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
  404. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
  405. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
  406. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
  407. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
  408. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
  409. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
  410. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
  411. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
  412. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
  413. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
  414. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
  415. package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
  416. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
  417. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
  418. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
  419. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
  420. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
  421. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
  422. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
  423. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
  424. package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
  425. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
  426. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
  427. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
  428. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
  429. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
  430. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
  431. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
  432. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
  433. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
  434. package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
  435. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
  436. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
  437. package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
  438. package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
  439. package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
  440. package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
  441. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
  442. package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
  443. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
  444. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
  445. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
  446. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
  447. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
  448. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
  449. package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
  450. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
  451. package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
  452. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
  453. package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
  454. package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
  455. package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
  456. package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
  457. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
  458. package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
  459. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
  460. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
  461. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
  462. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
  463. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
  464. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
  465. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
  466. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
  467. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
  468. package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
  469. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
  470. package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
  471. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
  472. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
  473. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
  474. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
  475. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
  476. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
  477. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
  478. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
  479. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
  480. package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
  481. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
  482. package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
  483. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
  484. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
  485. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
  486. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
  487. package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
  488. package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
  489. package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
  490. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
  491. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
  492. package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
  493. package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
  494. package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
  495. package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
  496. package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
  497. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
  498. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
  499. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
  500. package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
  501. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
  502. package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
  503. package/lib/vendor/blamejs/test/smoke.js +2 -0
  504. package/package.json +1 -1
  505. package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
  506. package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
  507. package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
  508. package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
  509. package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
  510. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
  511. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
  512. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
  513. package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
  514. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
  515. package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
  516. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
  517. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
  518. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
  519. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
  520. package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
  521. package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
  522. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
@@ -8,11 +8,17 @@
8
8
  * integration suite (test/integration/network-dns.test.js); this file
9
9
  * exercises the pure-parse paths (RFC 9460 §A sample wire formats)
10
10
  * and the operator-side DDR / DNR validation surface using fakes so
11
- * smoke runs offline.
11
+ * smoke runs offline. It also drives the public b.network.dns surface
12
+ * offline for the config-time throws, malformed-reply and name-decode
13
+ * branches, classifier edge cases, cache / IP-literal lookup paths,
14
+ * and raw-query transport failure branches — using loopback fake TCP
15
+ * responders + closed-port fault injection, never a real external
16
+ * endpoint and never rejectUnauthorized:false.
12
17
  */
13
18
 
14
19
  var net = require("node:net");
15
20
  var tls = require("node:tls");
21
+ var nodeHttps = require("node:https");
16
22
  var nodeCrypto = require("node:crypto");
17
23
 
18
24
  var helpers = require("../helpers");
@@ -251,6 +257,1665 @@ function testDnsErrorPermanentClassification() {
251
257
  check("DnsError dns/dot-failed is transient", new DnsError("dns/dot-failed", "x").permanent === false);
252
258
  }
253
259
 
260
+ // ---- Compact DNS wire-format builders (test-side) --------------------
261
+ // Terser siblings of the builders above, used by the error-branch and
262
+ // fault-injection tests; _buildReply additionally takes a flags word so
263
+ // tests can force non-NOERROR rcodes (SERVFAIL / NXDOMAIN).
264
+ function _qname(name) {
265
+ if (name === "" || name === ".") return Buffer.from([0]);
266
+ var parts = name.split(".").filter(Boolean);
267
+ var len = 1;
268
+ for (var i = 0; i < parts.length; i++) len += 1 + parts[i].length;
269
+ var buf = Buffer.alloc(len);
270
+ var off = 0;
271
+ for (var p = 0; p < parts.length; p++) {
272
+ var lab = parts[p];
273
+ buf.writeUInt8(lab.length, off++);
274
+ buf.write(lab, off, "ascii");
275
+ off += lab.length;
276
+ }
277
+ buf.writeUInt8(0, off);
278
+ return buf;
279
+ }
280
+
281
+ function _buildReply(qname, qtype, answers, flags) {
282
+ var qn = _qname(qname);
283
+ var qtail = Buffer.alloc(4);
284
+ qtail.writeUInt16BE(qtype, 0);
285
+ qtail.writeUInt16BE(1, 2);
286
+ var hdr = Buffer.alloc(12);
287
+ hdr.writeUInt16BE(0xabcd, 0);
288
+ hdr.writeUInt16BE(flags === undefined ? 0x8180 : flags, 2);
289
+ hdr.writeUInt16BE(1, 4);
290
+ hdr.writeUInt16BE(answers.length, 6);
291
+ var parts = [hdr, qn, qtail];
292
+ for (var a = 0; a < answers.length; a++) {
293
+ var ans = answers[a];
294
+ parts.push(_qname(ans.name || qname));
295
+ var ah = Buffer.alloc(10);
296
+ ah.writeUInt16BE(ans.type, 0);
297
+ ah.writeUInt16BE(1, 2);
298
+ ah.writeUInt32BE(ans.ttl || 60, 4);
299
+ ah.writeUInt16BE(ans.rdata.length, 8);
300
+ parts.push(ah, ans.rdata);
301
+ }
302
+ return Buffer.concat(parts);
303
+ }
304
+
305
+ function _svcbRd(priority, target, params) {
306
+ var prio = Buffer.alloc(2);
307
+ prio.writeUInt16BE(priority, 0);
308
+ var pieces = [prio, _qname(target)];
309
+ for (var i = 0; i < params.length; i++) {
310
+ var h = Buffer.alloc(4);
311
+ h.writeUInt16BE(params[i].key, 0);
312
+ h.writeUInt16BE(params[i].value.length, 2);
313
+ pieces.push(h, params[i].value);
314
+ }
315
+ return Buffer.concat(pieces);
316
+ }
317
+
318
+ function _alpn(protos) {
319
+ var pieces = [];
320
+ for (var i = 0; i < protos.length; i++) {
321
+ pieces.push(Buffer.from([protos[i].length]));
322
+ pieces.push(Buffer.from(protos[i], "ascii"));
323
+ }
324
+ return Buffer.concat(pieces);
325
+ }
326
+
327
+ // ---- fault-injection loopback fixtures --------------------------------
328
+ // Accepts the TCP connection then immediately tears it down — models an
329
+ // upstream that closes before sending any reply.
330
+ function _startCloseImmediately() {
331
+ return new Promise(function (resolve) {
332
+ var srv = net.createServer(function (sock) {
333
+ sock.on("error", function () { /* fixture best-effort */ });
334
+ sock.destroy();
335
+ });
336
+ srv.unref();
337
+ srv.listen(0, "127.0.0.1", function () {
338
+ resolve({ srv: srv, port: srv.address().port });
339
+ });
340
+ });
341
+ }
342
+
343
+ // A 127.0.0.1 port with nothing listening (bind → capture → close).
344
+ function _probeClosedPort() {
345
+ return new Promise(function (resolve) {
346
+ var s = net.createServer();
347
+ s.unref();
348
+ s.listen(0, "127.0.0.1", function () {
349
+ var p = s.address().port;
350
+ s.close(function () { resolve(p); });
351
+ });
352
+ });
353
+ }
354
+
355
+ // Track a server's live raw TCP sockets so teardown can force-close them.
356
+ // A plain srv.close() only stops accepting — stalled fixtures (hang mode)
357
+ // hold sockets open, which would otherwise outlive run() and trip the TCP
358
+ // handle-drain guard. `.close()` destroys every live connection first.
359
+ function _trackAndClosable(srv) {
360
+ var conns = new Set();
361
+ srv.on("connection", function (sock) {
362
+ conns.add(sock);
363
+ sock.on("close", function () { conns.delete(sock); });
364
+ });
365
+ return function close() {
366
+ conns.forEach(function (sock) {
367
+ try { sock.destroy(); } catch (_e) { /* best-effort */ }
368
+ });
369
+ try { srv.close(); } catch (_e) { /* best-effort */ }
370
+ };
371
+ }
372
+
373
+ // A loopback TCP responder that reads the framed query then cleanly
374
+ // half-closes (FIN) WITHOUT sending a reply — models an upstream that
375
+ // hangs up mid-exchange, driving the system-transport close-before-reply
376
+ // branch (distinct from an abrupt RST, which surfaces as 'error').
377
+ function _startTcpFinNoReply() {
378
+ return new Promise(function (resolve) {
379
+ var srv = net.createServer(function (sock) {
380
+ sock.on("error", function () { /* fixture best-effort */ });
381
+ sock.on("data", function () { sock.end(); }); // FIN after the query, no reply
382
+ });
383
+ srv.unref();
384
+ var close = _trackAndClosable(srv);
385
+ srv.listen(0, "127.0.0.1", function () {
386
+ resolve({ srv: srv, port: srv.address().port, close: close });
387
+ });
388
+ });
389
+ }
390
+
391
+ // A loopback TCP responder that accepts the connection, consumes the
392
+ // framed query, and NEVER replies — models an upstream that stalls after
393
+ // accept so the wall-clock deadline (sock.setTimeout) has to tear it down.
394
+ function _startTcpHang() {
395
+ return new Promise(function (resolve) {
396
+ var srv = net.createServer(function (sock) {
397
+ sock.on("data", function () { /* consume, never reply */ });
398
+ sock.on("error", function () { /* fixture best-effort */ });
399
+ });
400
+ srv.unref();
401
+ var close = _trackAndClosable(srv);
402
+ srv.listen(0, "127.0.0.1", function () {
403
+ resolve({ srv: srv, port: srv.address().port, close: close });
404
+ });
405
+ });
406
+ }
407
+
408
+ // ---- Real-handshake DoT / DoH fixtures --------------------------------
409
+ // The framework's DoT/DoH clients pin minVersion TLSv1.3 + the hybrid-PQC
410
+ // group list + a caller-supplied `ca`, and validate the server identity.
411
+ // We mint a server leaf through the framework's own mtls engine (SAN
412
+ // IP:127.0.0.1 + DNS:localhost) so a genuine TLS 1.3 handshake completes
413
+ // against a loopback listener with NO rejectUnauthorized:false anywhere.
414
+ // The cert keygen is the expensive part, so mint once and cache.
415
+ var _secureCertCache = null;
416
+ async function _mintSecureCert() {
417
+ if (_secureCertCache) return _secureCertCache;
418
+ var ca = await b.mtlsEngine.generateCa({ generation: 1 });
419
+ var leaf = await b.mtlsEngine.signClientCert({
420
+ cn: "localhost",
421
+ caCertPem: ca.caCertPem,
422
+ caKeyPem: ca.caKeyPem,
423
+ usage: "server",
424
+ sans: ["IP:127.0.0.1", "DNS:localhost"],
425
+ });
426
+ _secureCertCache = { caPem: ca.caCertPem, keyPem: leaf.key, certPem: leaf.cert };
427
+ return _secureCertCache;
428
+ }
429
+
430
+ // DoT (DNS-over-TLS) loopback responder. Speaks the 2-byte-length-prefixed
431
+ // TCP DNS framing over TLS 1.3. opts.hang completes the handshake then
432
+ // stalls; otherwise it replies once with opts.reply and half-closes.
433
+ function _startDotServer(cert, opts) {
434
+ opts = opts || {};
435
+ return new Promise(function (resolve) {
436
+ var srv = tls.createServer({
437
+ key: cert.keyPem,
438
+ cert: cert.certPem,
439
+ minVersion: "TLSv1.3",
440
+ }, function (sock) {
441
+ sock.on("error", function () { /* fixture best-effort */ });
442
+ if (opts.hang) return;
443
+ var got = [];
444
+ var expected = -1;
445
+ sock.on("data", function (chunk) {
446
+ got.push(chunk);
447
+ var all = Buffer.concat(got);
448
+ if (expected === -1 && all.length >= 2) expected = all.readUInt16BE(0);
449
+ if (expected >= 0 && all.length >= expected + 2) {
450
+ var rlen = Buffer.alloc(2);
451
+ rlen.writeUInt16BE(opts.reply.length, 0);
452
+ sock.write(rlen);
453
+ sock.write(opts.reply);
454
+ sock.end();
455
+ }
456
+ });
457
+ });
458
+ srv.on("error", function () { /* fixture best-effort */ });
459
+ srv.unref();
460
+ var close = _trackAndClosable(srv);
461
+ srv.listen(0, "127.0.0.1", function () {
462
+ resolve({ srv: srv, port: srv.address().port, close: close });
463
+ });
464
+ });
465
+ }
466
+
467
+ // DoH (DNS-over-HTTPS) loopback responder. Drains the request (GET query
468
+ // string or POST body) then answers with opts.reply under
469
+ // application/dns-message + opts.status (default 200). opts.hang receives
470
+ // the request and never responds so the per-request deadline fires.
471
+ function _startDohServer(cert, opts) {
472
+ opts = opts || {};
473
+ return new Promise(function (resolve) {
474
+ var srv = nodeHttps.createServer({
475
+ key: cert.keyPem,
476
+ cert: cert.certPem,
477
+ minVersion: "TLSv1.3",
478
+ }, function (req, res) {
479
+ req.on("error", function () { /* fixture best-effort */ });
480
+ req.on("data", function () { /* drain POST body */ });
481
+ req.on("end", function () {
482
+ if (opts.hang) return;
483
+ res.writeHead(opts.status || 200, { "content-type": "application/dns-message" });
484
+ res.end(opts.reply || Buffer.alloc(0));
485
+ });
486
+ });
487
+ srv.on("error", function () { /* fixture best-effort */ });
488
+ srv.unref();
489
+ var close = _trackAndClosable(srv);
490
+ srv.listen(0, "127.0.0.1", function () {
491
+ resolve({ srv: srv, port: srv.address().port, close: close });
492
+ });
493
+ });
494
+ }
495
+
496
+ // A record rdata (4 octets) + AAAA rdata (16 octets) builders for the
497
+ // transport round-trip fixtures.
498
+ function _aRdata(a, b2, c, d) { return Buffer.from([a, b2, c, d]); }
499
+ function _aaaaRdata() {
500
+ var v6 = Buffer.alloc(16);
501
+ v6[0] = 0x20; v6[1] = 0x01; v6[2] = 0x0d; v6[3] = 0xb8; v6[15] = 0x01; // 2001:db8::1
502
+ return v6;
503
+ }
504
+
505
+ // A reply whose single answer's owner name is a compression pointer
506
+ // (0xc0 0x0c → offset 12, the question name) instead of a fully-written
507
+ // name — the wire shape that exercises the name-compression branch of
508
+ // _skipDnsName that a literal owner name never reaches.
509
+ function _buildReplyCompressedName(qname, qtype, ansType, rdata, flags) {
510
+ var qn = _qname(qname);
511
+ var qtail = Buffer.alloc(4);
512
+ qtail.writeUInt16BE(qtype, 0);
513
+ qtail.writeUInt16BE(1, 2);
514
+ var hdr = Buffer.alloc(12);
515
+ hdr.writeUInt16BE(0xabcd, 0);
516
+ hdr.writeUInt16BE(flags === undefined ? 0x8180 : flags, 2);
517
+ hdr.writeUInt16BE(1, 4);
518
+ hdr.writeUInt16BE(1, 6);
519
+ var ptr = Buffer.from([0xc0, 0x0c]); // pointer → question name at offset 12
520
+ var ah = Buffer.alloc(10);
521
+ ah.writeUInt16BE(ansType, 0);
522
+ ah.writeUInt16BE(1, 2);
523
+ ah.writeUInt32BE(60, 4);
524
+ ah.writeUInt16BE(rdata.length, 8);
525
+ return Buffer.concat([hdr, qn, qtail, ptr, ah, rdata]);
526
+ }
527
+
528
+ function _reset() {
529
+ if (typeof dnsModule._resetForTest === "function") dnsModule._resetForTest();
530
+ }
531
+
532
+ // ======================================================================
533
+ // Config setters — throw-on-bad-input + success branches
534
+ // ======================================================================
535
+ function testSetServers() {
536
+ _reset();
537
+ check("setServers: non-array throws dns/bad-servers",
538
+ _throws(function () { dnsModule.setServers(null); }, "dns/bad-servers"));
539
+ check("setServers: empty array throws dns/bad-servers",
540
+ _throws(function () { dnsModule.setServers([]); }, "dns/bad-servers"));
541
+ check("setServers: non-string element throws dns/bad-server",
542
+ _throws(function () { dnsModule.setServers(["1.2.3.4", 123]); }, "dns/bad-server"));
543
+ check("setServers: empty-string element throws dns/bad-server",
544
+ _throws(function () { dnsModule.setServers(["1.2.3.4", ""]); }, "dns/bad-server"));
545
+ check("setServers: invalid resolver address throws dns/setservers-failed",
546
+ _throws(function () { dnsModule.setServers(["not-an-ip-at-all"]); }, "dns/setservers-failed"));
547
+
548
+ _reset();
549
+ dnsModule.setServers(["127.0.0.1", "9.9.9.9"]);
550
+ var got = dnsModule.getServers();
551
+ check("setServers: valid list persists + getServers returns a copy",
552
+ Array.isArray(got) && got.indexOf("127.0.0.1") !== -1 && got.indexOf("9.9.9.9") !== -1);
553
+ got.push("mutation");
554
+ check("getServers: returns a defensive copy (mutation does not leak)",
555
+ dnsModule.getServers().indexOf("mutation") === -1);
556
+ _reset();
557
+ check("getServers: falls back to OS resolvers (array) when unset",
558
+ Array.isArray(dnsModule.getServers()));
559
+ }
560
+
561
+ function testSetResultOrder() {
562
+ _reset();
563
+ check("setResultOrder: bad value throws dns/bad-result-order",
564
+ _throws(function () { dnsModule.setResultOrder("random"); }, "dns/bad-result-order"));
565
+ dnsModule.setResultOrder("ipv4first");
566
+ check("setResultOrder: ipv4first stored", dnsModule._stateForTest().resultOrder === "ipv4first");
567
+ dnsModule.setResultOrder("verbatim");
568
+ check("setResultOrder: verbatim stored", dnsModule._stateForTest().resultOrder === "verbatim");
569
+ dnsModule.setResultOrder("ipv6first");
570
+ check("setResultOrder: ipv6first stored (mapped to verbatim in node)",
571
+ dnsModule._stateForTest().resultOrder === "ipv6first");
572
+ _reset();
573
+ }
574
+
575
+ function testSetFamily() {
576
+ _reset();
577
+ check("setFamily: bad value throws dns/bad-family",
578
+ _throws(function () { dnsModule.setFamily(5); }, "dns/bad-family"));
579
+ dnsModule.setFamily(0);
580
+ check("setFamily: 0 accepted", dnsModule._stateForTest().family === 0);
581
+ dnsModule.setFamily(4);
582
+ check("setFamily: 4 accepted", dnsModule._stateForTest().family === 4);
583
+ dnsModule.setFamily(6);
584
+ check("setFamily: 6 accepted", dnsModule._stateForTest().family === 6);
585
+ _reset();
586
+ }
587
+
588
+ function testSetLookupTimeout() {
589
+ _reset();
590
+ check("setLookupTimeoutMs: non-number throws dns/bad-timeout",
591
+ _throws(function () { dnsModule.setLookupTimeoutMs("5s"); }, "dns/bad-timeout"));
592
+ check("setLookupTimeoutMs: NaN throws dns/bad-timeout",
593
+ _throws(function () { dnsModule.setLookupTimeoutMs(NaN); }, "dns/bad-timeout"));
594
+ check("setLookupTimeoutMs: Infinity throws dns/bad-timeout",
595
+ _throws(function () { dnsModule.setLookupTimeoutMs(Infinity); }, "dns/bad-timeout"));
596
+ check("setLookupTimeoutMs: negative throws dns/bad-timeout",
597
+ _throws(function () { dnsModule.setLookupTimeoutMs(-1); }, "dns/bad-timeout"));
598
+ dnsModule.setLookupTimeoutMs(1234);
599
+ check("setLookupTimeoutMs: valid value stored", dnsModule._stateForTest().lookupTimeoutMs === 1234);
600
+ _reset();
601
+ }
602
+
603
+ function testSetCacheTtl() {
604
+ _reset();
605
+ check("setCacheTtlMs: non-number throws dns/bad-cache-ttl",
606
+ _throws(function () { dnsModule.setCacheTtlMs("nope"); }, "dns/bad-cache-ttl"));
607
+ check("setCacheTtlMs: negative throws dns/bad-cache-ttl",
608
+ _throws(function () { dnsModule.setCacheTtlMs(-5); }, "dns/bad-cache-ttl"));
609
+ check("setCacheTtlMs: bad negativeMs throws dns/bad-cache-ttl",
610
+ _throws(function () { dnsModule.setCacheTtlMs(1000, -1); }, "dns/bad-cache-ttl"));
611
+ dnsModule.setCacheTtlMs(5000, 2500);
612
+ check("setCacheTtlMs: positive ms + negativeMs stored",
613
+ dnsModule._stateForTest().cacheTtlMs === 5000 &&
614
+ dnsModule._stateForTest().cacheNegativeTtlMs === 2500);
615
+ dnsModule.setCacheTtlMs(0);
616
+ check("setCacheTtlMs: 0 disables + clears (cacheTtlMs=0)",
617
+ dnsModule._stateForTest().cacheTtlMs === 0);
618
+ _reset();
619
+ }
620
+
621
+ function testUseDnsOverHttps() {
622
+ _reset();
623
+ dnsModule.useDnsOverHttps({ provider: "cloudflare" });
624
+ check("useDnsOverHttps: provider=cloudflare resolves url",
625
+ dnsModule._stateForTest().doh.url.indexOf("cloudflare-dns.com") !== -1);
626
+ _reset();
627
+ dnsModule.useDnsOverHttps({ provider: "google" });
628
+ check("useDnsOverHttps: provider=google resolves url",
629
+ dnsModule._stateForTest().doh.url.indexOf("dns.google") !== -1);
630
+ _reset();
631
+ dnsModule.useDnsOverHttps({ provider: "quad9" });
632
+ check("useDnsOverHttps: provider=quad9 resolves url",
633
+ dnsModule._stateForTest().doh.url.indexOf("quad9") !== -1);
634
+ _reset();
635
+ check("useDnsOverHttps: unknown provider throws dns/bad-doh-provider",
636
+ _throws(function () { dnsModule.useDnsOverHttps({ provider: "myisp" }); }, "dns/bad-doh-provider"));
637
+ check("useDnsOverHttps: non-https url throws dns/bad-doh-url",
638
+ _throws(function () { dnsModule.useDnsOverHttps({ url: "http://insecure/dns" }); }, "dns/bad-doh-url"));
639
+ check("useDnsOverHttps: bad method throws dns/bad-doh-method",
640
+ _throws(function () { dnsModule.useDnsOverHttps({ url: "https://x/dns", method: "PUT" }); }, "dns/bad-doh-method"));
641
+ check("useDnsOverHttps: bad ca type throws dns/bad-doh-ca",
642
+ _throws(function () { dnsModule.useDnsOverHttps({ url: "https://x/dns", ca: 123 }); }, "dns/bad-doh-ca"));
643
+ check("useDnsOverHttps: unknown opt key throws (validate-opts)",
644
+ _throws(function () { dnsModule.useDnsOverHttps({ url: "https://x/dns", bogus: 1 }); }));
645
+ _reset();
646
+ dnsModule.useDnsOverHttps({ url: "https://doh.example/dns-query", method: "POST" });
647
+ check("useDnsOverHttps: explicit url+method configured",
648
+ dnsModule._stateForTest().doh.url === "https://doh.example/dns-query" &&
649
+ dnsModule._stateForTest().doh.method === "POST");
650
+ _reset();
651
+ }
652
+
653
+ function testUseDnsOverTls() {
654
+ _reset();
655
+ check("useDnsOverTls: missing host throws dns/bad-dot-host",
656
+ _throws(function () { dnsModule.useDnsOverTls({ port: 853 }); }, "dns/bad-dot-host"));
657
+ check("useDnsOverTls: bad port throws dns/bad-dot-port",
658
+ _throws(function () { dnsModule.useDnsOverTls({ host: "1.1.1.1", port: -5 }); }, "dns/bad-dot-port"));
659
+ check("useDnsOverTls: bad ca type throws dns/bad-dot-ca",
660
+ _throws(function () { dnsModule.useDnsOverTls({ host: "1.1.1.1", ca: 42 }); }, "dns/bad-dot-ca"));
661
+ check("useDnsOverTls: unknown opt key throws (validate-opts)",
662
+ _throws(function () { dnsModule.useDnsOverTls({ host: "1.1.1.1", nope: 1 }); }));
663
+ _reset();
664
+ dnsModule.useDnsOverTls({ host: "1.1.1.1" });
665
+ var st = dnsModule._stateForTest();
666
+ check("useDnsOverTls: defaults port 853 + servername=host",
667
+ st.dot.host === "1.1.1.1" && st.dot.port === 853 && st.dot.servername === "1.1.1.1");
668
+ _reset();
669
+ }
670
+
671
+ function testUseSystemResolver() {
672
+ _reset();
673
+ dnsModule.useDnsOverHttps({ url: "https://x/dns" });
674
+ dnsModule.useSystemResolver();
675
+ var st = dnsModule._stateForTest();
676
+ check("useSystemResolver: clears doh/dot + sets systemResolver",
677
+ st.doh === null && st.dot === null && st.systemResolver === true);
678
+ _reset();
679
+ }
680
+
681
+ // ======================================================================
682
+ // Classifiers — pure, never throw
683
+ // ======================================================================
684
+ function testIsNullMx() {
685
+ check("isNullMx: non-array is false", dnsModule.isNullMx(null) === false);
686
+ check("isNullMx: empty array is false", dnsModule.isNullMx([]) === false);
687
+ check("isNullMx: two records is false",
688
+ dnsModule.isNullMx([{ priority: 0, exchange: "." }, { priority: 1, exchange: "mx" }]) === false);
689
+ check("isNullMx: non-object element is false", dnsModule.isNullMx([null]) === false);
690
+ check("isNullMx: non-zero priority is false",
691
+ dnsModule.isNullMx([{ priority: 10, exchange: "." }]) === false);
692
+ check("isNullMx: priority 0 + exchange '' is null-mx (node shape)",
693
+ dnsModule.isNullMx([{ priority: 0, exchange: "" }]) === true);
694
+ check("isNullMx: priority 0 + exchange '.' is null-mx (literal root)",
695
+ dnsModule.isNullMx([{ priority: 0, exchange: "." }]) === true);
696
+ check("isNullMx: real exchange is not null-mx",
697
+ dnsModule.isNullMx([{ priority: 0, exchange: "mail.example.com" }]) === false);
698
+ }
699
+
700
+ function testClassifyDnskeyAlgorithm() {
701
+ check("classifyDnskeyAlgorithm: non-integer returns null",
702
+ dnsModule.classifyDnskeyAlgorithm(1.5) === null);
703
+ check("classifyDnskeyAlgorithm: string returns null",
704
+ dnsModule.classifyDnskeyAlgorithm("13") === null);
705
+ check("classifyDnskeyAlgorithm: NaN returns null",
706
+ dnsModule.classifyDnskeyAlgorithm(NaN) === null);
707
+ var sha1 = dnsModule.classifyDnskeyAlgorithm(5);
708
+ check("classifyDnskeyAlgorithm: 5 RSASHA1 deprecated+known",
709
+ sha1 && sha1.deprecated === true && sha1.known === true && sha1.name === "RSASHA1");
710
+ var ec = dnsModule.classifyDnskeyAlgorithm(13);
711
+ check("classifyDnskeyAlgorithm: 13 ECDSAP256SHA256 current",
712
+ ec && ec.deprecated === false && ec.known === true);
713
+ var reserved = dnsModule.classifyDnskeyAlgorithm(4);
714
+ check("classifyDnskeyAlgorithm: 4 Reserved is deprecated+known",
715
+ reserved && reserved.deprecated === true && reserved.known === true);
716
+ var unassigned = dnsModule.classifyDnskeyAlgorithm(17);
717
+ check("classifyDnskeyAlgorithm: 17 unassigned → known:false",
718
+ unassigned && unassigned.known === false && unassigned.deprecated === false);
719
+ var priv = dnsModule.classifyDnskeyAlgorithm(253);
720
+ check("classifyDnskeyAlgorithm: 253 PRIVATEDNS known+not-deprecated",
721
+ priv && priv.known === true && priv.deprecated === false);
722
+ }
723
+
724
+ function testClassifyDsDigestType() {
725
+ check("classifyDsDigestType: non-integer returns null",
726
+ dnsModule.classifyDsDigestType(2.2) === null);
727
+ var sha1 = dnsModule.classifyDsDigestType(1);
728
+ check("classifyDsDigestType: 1 SHA-1 deprecated+known",
729
+ sha1 && sha1.deprecated === true && sha1.known === true);
730
+ var sha256 = dnsModule.classifyDsDigestType(2);
731
+ check("classifyDsDigestType: 2 SHA-256 current",
732
+ sha256 && sha256.deprecated === false && sha256.known === true);
733
+ var reserved = dnsModule.classifyDsDigestType(0);
734
+ check("classifyDsDigestType: 0 Reserved deprecated+known",
735
+ reserved && reserved.deprecated === true && reserved.known === true);
736
+ var unassigned = dnsModule.classifyDsDigestType(7);
737
+ check("classifyDsDigestType: 7 unassigned → known:false",
738
+ unassigned && unassigned.known === false);
739
+ }
740
+
741
+ // ======================================================================
742
+ // SVCB rdata parse — malformed + valid variants (direct call)
743
+ // ======================================================================
744
+ function _parseAt0(rd) { return dnsModule._parseSvcbRdata(rd, 0, rd.length); }
745
+
746
+ function testParseSvcbMalformed() {
747
+ var parse = dnsModule._parseSvcbRdata;
748
+ check("parseSvcb: rdlen < 2 throws (truncated before priority)",
749
+ _throws(function () { parse(Buffer.alloc(4), 0, 1); }, "dns/svcb-malformed"));
750
+
751
+ // priority(2) + root name(0x00) + 3 dangling bytes → SvcParam header truncated
752
+ var hdrTrunc = Buffer.concat([Buffer.from([0, 1]), Buffer.from([0]), Buffer.from([0, 0, 0])]);
753
+ check("parseSvcb: dangling SvcParam header throws (header truncated)",
754
+ _throws(function () { return _parseAt0(hdrTrunc); }, "dns/svcb-malformed"));
755
+
756
+ // key present but paramLen overflows rdata
757
+ var overflow = Buffer.concat([Buffer.from([0, 1]), Buffer.from([0]),
758
+ Buffer.from([0, 1]), Buffer.from([0, 5])]);
759
+ check("parseSvcb: SvcParam value overflow throws",
760
+ _throws(function () { return _parseAt0(overflow); }, "dns/svcb-malformed"));
761
+
762
+ check("parseSvcb: mandatory odd length throws",
763
+ _throws(function () {
764
+ return _parseAt0(_svcbRd(1, ".", [{ key: 0, value: Buffer.from([0]) }]));
765
+ }, "dns/svcb-malformed"));
766
+ check("parseSvcb: no-default-alpn with non-zero length throws",
767
+ _throws(function () {
768
+ return _parseAt0(_svcbRd(1, ".", [{ key: 2, value: Buffer.from([0]) }]));
769
+ }, "dns/svcb-malformed"));
770
+ check("parseSvcb: port wrong length throws",
771
+ _throws(function () {
772
+ return _parseAt0(_svcbRd(1, ".", [{ key: 3, value: Buffer.from([1]) }]));
773
+ }, "dns/svcb-malformed"));
774
+ check("parseSvcb: ipv4hint length not multiple of 4 throws",
775
+ _throws(function () {
776
+ return _parseAt0(_svcbRd(1, ".", [{ key: 4, value: Buffer.from([1, 2, 3]) }]));
777
+ }, "dns/svcb-malformed"));
778
+ check("parseSvcb: ipv6hint length not multiple of 16 throws",
779
+ _throws(function () {
780
+ return _parseAt0(_svcbRd(1, ".", [{ key: 6, value: Buffer.alloc(15) }]));
781
+ }, "dns/svcb-malformed"));
782
+ check("parseSvcb: alpn char-string overflow throws",
783
+ _throws(function () {
784
+ return _parseAt0(_svcbRd(1, ".", [{ key: 1, value: Buffer.from([5]) }]));
785
+ }, "dns/svcb-malformed"));
786
+ }
787
+
788
+ function testParseSvcbValidVariants() {
789
+ // no-default-alpn (key 2, zero length) → noDefaultAlpn true
790
+ var ndAlpn = _parseAt0(_svcbRd(1, "svc.example.net", [{ key: 2, value: Buffer.alloc(0) }]));
791
+ check("parseSvcb: no-default-alpn (zero length) → noDefaultAlpn true",
792
+ ndAlpn.params.noDefaultAlpn === true);
793
+
794
+ // AliasMode with root target "." → target "."
795
+ var rootAlias = _parseAt0(Buffer.concat([Buffer.from([0, 0]), _qname(".")]));
796
+ check("parseSvcb: root target renders as '.'",
797
+ rootAlias.priority === 0 && rootAlias.target === ".");
798
+
799
+ // dohpath (key 7) utf8
800
+ var dp = _parseAt0(_svcbRd(2, "svc.example.net",
801
+ [{ key: 7, value: Buffer.from("/dns-query{?dns}", "utf8") }]));
802
+ check("parseSvcb: dohpath decodes utf8", dp.params.dohpath === "/dns-query{?dns}");
803
+
804
+ // ech (key 5) opaque buffer
805
+ var ech = _parseAt0(_svcbRd(3, "svc.example.net",
806
+ [{ key: 5, value: Buffer.from([0xfe, 0x0d, 0x00]) }]));
807
+ check("parseSvcb: ech surfaced as opaque buffer",
808
+ Buffer.isBuffer(ech.params.ech) && ech.params.ech.length === 3);
809
+ }
810
+
811
+ // ======================================================================
812
+ // _decodeDnsAnswerRaw — adversarial reply framing (direct call)
813
+ // ======================================================================
814
+ function testDecodeAnswerRaw() {
815
+ var dec = dnsModule._decodeDnsAnswerRaw;
816
+ check("_decodeDnsAnswerRaw: non-buffer throws dns/bad-reply",
817
+ _throws(function () { dec("notabuffer"); }, "dns/bad-reply"));
818
+ check("_decodeDnsAnswerRaw: <12 bytes throws dns/bad-reply",
819
+ _throws(function () { dec(Buffer.alloc(6)); }, "dns/bad-reply"));
820
+
821
+ // rcode != 0 (SERVFAIL=2) → dns/no-result
822
+ var servfail = Buffer.alloc(12);
823
+ servfail.writeUInt8(0x02, 3);
824
+ check("_decodeDnsAnswerRaw: non-zero rcode throws dns/no-result",
825
+ _throws(function () { dec(servfail); }, "dns/no-result"));
826
+
827
+ // ancount claims 1 but no answer bytes follow the question → record truncated
828
+ var recTrunc = _buildReply("example.com", 1, []);
829
+ recTrunc.writeUInt16BE(1, 6); // lie: ancount = 1
830
+ check("_decodeDnsAnswerRaw: answer record header truncated throws dns/bad-reply",
831
+ _throws(function () { dec(recTrunc); }, "dns/bad-reply"));
832
+
833
+ // valid A answer but rdlen lies past buffer end → rdata truncated
834
+ var okReply = _buildReply("example.com", 1,
835
+ [{ name: "example.com", type: 1, rdata: Buffer.from([1, 2, 3, 4]) }]);
836
+ // bump the last answer's rdlen (offset = length-2-4) to overflow
837
+ okReply.writeUInt16BE(0x00ff, okReply.length - 6);
838
+ check("_decodeDnsAnswerRaw: answer rdata truncated throws dns/bad-reply",
839
+ _throws(function () { dec(okReply); }, "dns/bad-reply"));
840
+
841
+ // clean decode of a well-formed reply
842
+ var clean = dec(_buildReply("example.com", 1,
843
+ [{ name: "example.com", type: 1, rdata: Buffer.from([9, 9, 9, 9]) }]));
844
+ check("_decodeDnsAnswerRaw: well-formed reply yields one answer + ad=false",
845
+ clean.answers.length === 1 && clean.ad === false);
846
+ }
847
+
848
+ // ======================================================================
849
+ // _readDnsName — pointer + termination adversarial branches (direct call)
850
+ // ======================================================================
851
+ function testReadDnsName() {
852
+ var rd = dnsModule._readDnsName;
853
+
854
+ // compression pointer as the very last byte → truncated at pointer
855
+ var ptrTrunc = Buffer.from([0xc0]);
856
+ check("_readDnsName: pointer truncated at last byte throws",
857
+ _throws(function () { rd(ptrTrunc, 0); }, "dns/svcb-malformed"));
858
+
859
+ // pointer target beyond buffer length → out of bounds
860
+ var ptrOob = Buffer.from([0xc0, 0x40]); // points to offset 64, buf len 2
861
+ check("_readDnsName: pointer out of bounds throws",
862
+ _throws(function () { rd(ptrOob, 0); }, "dns/svcb-malformed"));
863
+
864
+ // labels with no terminating 0 and no pointer → not terminated
865
+ var noTerm = Buffer.from([3, 0x61, 0x62, 0x63]); // "abc" then EOF
866
+ check("_readDnsName: unterminated name throws",
867
+ _throws(function () { rd(noTerm, 0); }, "dns/svcb-malformed"));
868
+
869
+ // valid: two labels then root
870
+ var ok = Buffer.concat([_qname("a.bc")]);
871
+ var res = rd(ok, 0);
872
+ check("_readDnsName: valid name decodes labels + nextOff",
873
+ res.name === "a.bc" && res.nextOff === ok.length);
874
+
875
+ // valid forward compression pointer: name at 0 = "x" + pointer to a
876
+ // root label sitting later in the buffer.
877
+ var buf = Buffer.alloc(8);
878
+ buf[0] = 1; buf[1] = 0x78; // label "x"
879
+ buf[2] = 0xc0; buf[3] = 0x05; // pointer to offset 5
880
+ buf[5] = 0; // root at offset 5
881
+ var pres = rd(buf, 0);
882
+ check("_readDnsName: forward pointer resolves + nextOff after pointer",
883
+ pres.name === "x" && pres.nextOff === 4);
884
+ }
885
+
886
+ // ======================================================================
887
+ // lookup — IP literal short-circuit + cache + local-form system path
888
+ // ======================================================================
889
+ async function testLookupIpLiteral() {
890
+ _reset();
891
+ var v4 = await dnsModule.lookup("203.0.113.7");
892
+ check("lookup: IPv4 literal returns {address,family:4} without resolution",
893
+ v4.address === "203.0.113.7" && v4.family === 4);
894
+ var v4all = await dnsModule.lookup("203.0.113.7", { all: true });
895
+ check("lookup: IPv4 literal all:true returns single-element array",
896
+ Array.isArray(v4all) && v4all.length === 1 && v4all[0].family === 4);
897
+ var v6 = await dnsModule.lookup("2001:db8::1");
898
+ check("lookup: IPv6 literal returns family 6", v6.family === 6);
899
+ _reset();
900
+ }
901
+
902
+ async function testLookupLocalFormAndCache() {
903
+ _reset();
904
+ dnsModule.setCacheTtlMs(60000);
905
+ dnsModule.setLookupTimeoutMs(4000);
906
+ var first = await dnsModule.lookup("localhost");
907
+ check("lookup: localhost resolves via system path (loopback)",
908
+ typeof first.address === "string" && (first.family === 4 || first.family === 6));
909
+ var second = await dnsModule.lookup("localhost");
910
+ check("lookup: second localhost lookup returns same address (positive cache hit)",
911
+ first.address === second.address);
912
+ var allForm = await dnsModule.lookup("localhost", { all: true });
913
+ check("lookup: all:true from cache returns array", Array.isArray(allForm));
914
+ dnsModule.clearCache();
915
+ var third = await dnsModule.lookup("localhost");
916
+ check("lookup: resolves again after clearCache", typeof third.address === "string");
917
+ _reset();
918
+ }
919
+
920
+ async function testLookupNegativeCache() {
921
+ _reset();
922
+ dnsModule.useSystemResolver();
923
+ dnsModule.setCacheTtlMs(60000, 60000);
924
+ dnsModule.setLookupTimeoutMs(4000);
925
+ var e1 = null;
926
+ try { await dnsModule.lookup("no-such-host-zzz.invalid"); }
927
+ catch (e) { e1 = e; }
928
+ if (e1) {
929
+ var e2 = null;
930
+ try { await dnsModule.lookup("no-such-host-zzz.invalid"); }
931
+ catch (e) { e2 = e; }
932
+ check("lookup: negative cache re-throws the SAME error instance (cache hit)",
933
+ e2 !== null && e2 === e1);
934
+ } else {
935
+ check("lookup: negative-cache path (host unexpectedly resolved; skipped)", true);
936
+ }
937
+ _reset();
938
+ }
939
+
940
+ async function testLookupOrderingBranches() {
941
+ // Drive _orderAddrs ipv6first + ipv4first sort branches through the
942
+ // local-form system path (localhost may return >=1 address).
943
+ _reset();
944
+ dnsModule.setResultOrder("ipv6first");
945
+ dnsModule.setLookupTimeoutMs(4000);
946
+ var a = await dnsModule.lookup("localhost", { all: true });
947
+ check("lookup: ipv6first ordering path returns array", Array.isArray(a) && a.length >= 1);
948
+ _reset();
949
+ dnsModule.setResultOrder("ipv4first");
950
+ dnsModule.setLookupTimeoutMs(4000);
951
+ var c = await dnsModule.lookup("localhost", { all: true });
952
+ check("lookup: ipv4first ordering path returns array", Array.isArray(c) && c.length >= 1);
953
+ _reset();
954
+ }
955
+
956
+ async function testLookupDohDotNoResult() {
957
+ // DoH configured but pointed at a closed port: _dualStack catches both
958
+ // family failures → normalized empty → dns/no-result.
959
+ _reset();
960
+ var closed = await _probeClosedPort();
961
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + closed + "/dns-query" });
962
+ dnsModule.setLookupTimeoutMs(1500);
963
+ check("lookup(DoH, dead upstream): both families fail → dns/no-result",
964
+ await _throwsAsync(function () { return dnsModule.lookup("public.example.com"); }, "dns/no-result"));
965
+ _reset();
966
+
967
+ // DoT configured at a closed port: handshake failure per family → empty → no-result.
968
+ var closed2 = await _probeClosedPort();
969
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: closed2, servername: "localhost" });
970
+ dnsModule.setLookupTimeoutMs(1500);
971
+ check("lookup(DoT, dead upstream): handshake fails → dns/no-result",
972
+ await _throwsAsync(function () { return dnsModule.lookup("public.example.com"); }, "dns/no-result"));
973
+ await _drainTcpHandles();
974
+ }
975
+
976
+ // ======================================================================
977
+ // resolve / _resolveProtocol — IP literal, wrong-family, transport errors
978
+ // ======================================================================
979
+ async function testResolveProtocol() {
980
+ _reset();
981
+ check("resolve4: bad host throws dns/bad-host",
982
+ await _throwsAsync(function () { return dnsModule.resolve4(""); }, "dns/bad-host"));
983
+ var r4 = await dnsModule.resolve4("198.51.100.9");
984
+ check("resolve4: IPv4 literal short-circuits to [literal]",
985
+ Array.isArray(r4) && r4[0] === "198.51.100.9");
986
+ check("resolve4: IPv6 literal is wrong family",
987
+ await _throwsAsync(function () { return dnsModule.resolve4("2001:db8::5"); }, "dns/wrong-family"));
988
+ var r6 = await dnsModule.resolve6("2001:db8::5");
989
+ check("resolve6: IPv6 literal short-circuits", Array.isArray(r6) && r6[0] === "2001:db8::5");
990
+ check("resolve6: IPv4 literal is wrong family",
991
+ await _throwsAsync(function () { return dnsModule.resolve6("198.51.100.9"); }, "dns/wrong-family"));
992
+ var r6a = await dnsModule.resolveAaaa("2001:db8::9");
993
+ check("resolveAaaa: IPv6 literal short-circuits", Array.isArray(r6a) && r6a[0] === "2001:db8::9");
994
+ _reset();
995
+ }
996
+
997
+ async function testResolveTransportErrors() {
998
+ _reset();
999
+ var closed = await _probeClosedPort();
1000
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + closed + "/dns-query" });
1001
+ dnsModule.setLookupTimeoutMs(1500);
1002
+ check("resolve4(auto DoH, dead upstream): surfaces DnsError",
1003
+ await _throwsAsync(function () { return dnsModule.resolve4("public.example.com"); }));
1004
+ _reset();
1005
+
1006
+ var closed2 = await _probeClosedPort();
1007
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: closed2, servername: "localhost" });
1008
+ dnsModule.setLookupTimeoutMs(1500);
1009
+ check("resolve4(auto DoT, dead upstream): surfaces DnsError",
1010
+ await _throwsAsync(function () { return dnsModule.resolve4("public.example.com"); }));
1011
+ await _drainTcpHandles();
1012
+ }
1013
+
1014
+ async function testResolveDispatch() {
1015
+ _reset();
1016
+ // lowercase type is uppercased; A dispatch via IP literal (offline).
1017
+ var a = await dnsModule.resolve("192.0.2.10", "a");
1018
+ check("resolve: lowercase 'a' dispatches to A + short-circuits literal",
1019
+ Array.isArray(a) && a[0] === "192.0.2.10");
1020
+ var aaaa = await dnsModule.resolve("2001:db8::7", "aaaa");
1021
+ check("resolve: 'aaaa' dispatches to AAAA literal",
1022
+ Array.isArray(aaaa) && aaaa[0] === "2001:db8::7");
1023
+ check("resolve: unsupported type throws dns/unsupported-type",
1024
+ await _throwsAsync(function () { return dnsModule.resolve("example.com", "TXT"); }, "dns/unsupported-type"));
1025
+
1026
+ // HTTPS dispatch → queryHttps, exercised via a system TCP responder.
1027
+ var reply = _buildReply("example.com", 65, [{
1028
+ name: "example.com", type: 65,
1029
+ rdata: _svcbRd(1, "svc.example.net", [{ key: 1, value: _alpn(["h2"]) }]),
1030
+ }]);
1031
+ var fix = await _startTcpResponder(reply);
1032
+ dnsModule.useSystemResolver();
1033
+ dnsModule.setServers(["127.0.0.1:" + fix.port]);
1034
+ dnsModule.setLookupTimeoutMs(5000);
1035
+ var https = await dnsModule.resolve("example.com", "HTTPS", { transport: "system" });
1036
+ check("resolve: 'HTTPS' dispatches to queryHttps (system transport)",
1037
+ Array.isArray(https) && https.length === 1 && https[0].params.alpn[0] === "h2");
1038
+ fix.srv.close();
1039
+ await _drainTcpHandles();
1040
+ }
1041
+
1042
+ // ======================================================================
1043
+ // resolveSecure — validation branches + DoH error path
1044
+ // ======================================================================
1045
+ async function testResolveSecure() {
1046
+ _reset();
1047
+ dnsModule.useSystemResolver();
1048
+ check("resolveSecure: no DoH transport throws dns/secure-requires-doh",
1049
+ await _throwsAsync(function () { return dnsModule.resolveSecure("example.com"); }, "dns/secure-requires-doh"));
1050
+ _reset();
1051
+ dnsModule.useDnsOverHttps({ url: "https://x.example/dns-query" });
1052
+ check("resolveSecure: empty host throws dns/bad-host",
1053
+ await _throwsAsync(function () { return dnsModule.resolveSecure(""); }, "dns/bad-host"));
1054
+ check("resolveSecure: >253 char host throws dns/bad-host",
1055
+ await _throwsAsync(function () {
1056
+ return dnsModule.resolveSecure(("a".repeat(60) + ".").repeat(5) + "example.com");
1057
+ }, "dns/bad-host"));
1058
+ check("resolveSecure: oversize label throws dns/bad-host",
1059
+ await _throwsAsync(function () {
1060
+ return dnsModule.resolveSecure("a".repeat(64) + ".example.com");
1061
+ }, "dns/bad-host"));
1062
+ check("resolveSecure: non-LDH label (underscore) throws dns/bad-host",
1063
+ await _throwsAsync(function () {
1064
+ return dnsModule.resolveSecure("bad_label.example.com");
1065
+ }, "dns/bad-host"));
1066
+ check("resolveSecure: unsupported type throws dns/secure-unsupported-type",
1067
+ await _throwsAsync(function () {
1068
+ return dnsModule.resolveSecure("example.com", "TXT");
1069
+ }, "dns/secure-unsupported-type"));
1070
+ _reset();
1071
+
1072
+ // Valid host + type but dead DoH upstream → DoH error path executes.
1073
+ var closed = await _probeClosedPort();
1074
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + closed + "/dns-query" });
1075
+ dnsModule.setLookupTimeoutMs(1500);
1076
+ check("resolveSecure: valid A query against dead upstream surfaces DnsError",
1077
+ await _throwsAsync(function () { return dnsModule.resolveSecure("example.com", "A"); }));
1078
+ check("resolveSecure: valid AAAA query against dead upstream surfaces DnsError",
1079
+ await _throwsAsync(function () { return dnsModule.resolveSecure("example.com", "AAAA"); }));
1080
+ await _drainTcpHandles();
1081
+ }
1082
+
1083
+ // ======================================================================
1084
+ // reverse — input validation
1085
+ // ======================================================================
1086
+ async function testReverse() {
1087
+ _reset();
1088
+ check("reverse: non-string throws dns/bad-ip",
1089
+ await _throwsAsync(function () { return dnsModule.reverse(12345); }, "dns/bad-ip"));
1090
+ check("reverse: empty string throws dns/bad-ip",
1091
+ await _throwsAsync(function () { return dnsModule.reverse(""); }, "dns/bad-ip"));
1092
+ check("reverse: non-IP string throws dns/bad-ip",
1093
+ await _throwsAsync(function () { return dnsModule.reverse("definitely-not-an-ip"); }, "dns/bad-ip"));
1094
+ _reset();
1095
+ }
1096
+
1097
+ // ======================================================================
1098
+ // nodeLookup — callback adapter (offline via IP literal + local form)
1099
+ // ======================================================================
1100
+ function _nodeLookupP(host, options) {
1101
+ return new Promise(function (resolve, reject) {
1102
+ function cb(err) {
1103
+ if (err) return reject(err);
1104
+ resolve(Array.prototype.slice.call(arguments, 1));
1105
+ }
1106
+ if (options === undefined) dnsModule.nodeLookup(host, cb);
1107
+ else dnsModule.nodeLookup(host, options, cb);
1108
+ });
1109
+ }
1110
+
1111
+ async function testNodeLookup() {
1112
+ _reset();
1113
+ var single = await _nodeLookupP("192.0.2.55"); // options omitted → function-as-options branch
1114
+ check("nodeLookup: options-omitted callback yields (address, family)",
1115
+ single[0] === "192.0.2.55" && single[1] === 4);
1116
+ var all = await _nodeLookupP("192.0.2.55", { all: true });
1117
+ check("nodeLookup: all:true yields an array in first callback arg",
1118
+ Array.isArray(all[0]) && all[0][0].address === "192.0.2.55");
1119
+
1120
+ // error path via callback (local-form NXDOMAIN)
1121
+ dnsModule.useSystemResolver();
1122
+ dnsModule.setLookupTimeoutMs(4000);
1123
+ var errored = false;
1124
+ try { await _nodeLookupP("no-host-abc-xyz.invalid"); }
1125
+ catch (e) { errored = !!e; }
1126
+ check("nodeLookup: resolution failure surfaces via callback(err)", errored);
1127
+ _reset();
1128
+ }
1129
+
1130
+ // ======================================================================
1131
+ // _systemRawQuery — transport failure branches (loopback fixtures)
1132
+ // ======================================================================
1133
+ async function testSystemRawQueryErrors() {
1134
+ // Upstream closes before replying → dns/system-failed.
1135
+ _reset();
1136
+ var closer = await _startCloseImmediately();
1137
+ dnsModule.useSystemResolver();
1138
+ dnsModule.setServers(["127.0.0.1:" + closer.port]);
1139
+ dnsModule.setLookupTimeoutMs(3000);
1140
+ check("querySvcb(system): upstream close-before-reply → dns/system-failed",
1141
+ await _throwsAsync(function () {
1142
+ return dnsModule.querySvcb("example.com", { transport: "system" });
1143
+ }, "dns/system-failed"));
1144
+ closer.srv.close();
1145
+ await _drainTcpHandles();
1146
+
1147
+ // Connection refused → dns/system-failed.
1148
+ _reset();
1149
+ var refused = await _probeClosedPort();
1150
+ dnsModule.useSystemResolver();
1151
+ dnsModule.setServers(["127.0.0.1:" + refused]);
1152
+ dnsModule.setLookupTimeoutMs(3000);
1153
+ check("querySvcb(system): connection refused → dns/system-failed",
1154
+ await _throwsAsync(function () {
1155
+ return dnsModule.querySvcb("example.com", { transport: "system" });
1156
+ }, "dns/system-failed"));
1157
+ await _drainTcpHandles();
1158
+ }
1159
+
1160
+ async function testSystemRawQueryV6Bracket() {
1161
+ // Exercise the "[ipv6]:port" server-address parsing branch. Best-effort:
1162
+ // skips cleanly when the runner lacks IPv6 loopback.
1163
+ _reset();
1164
+ var port = null;
1165
+ try {
1166
+ port = await new Promise(function (resolve, reject) {
1167
+ var s = net.createServer();
1168
+ s.unref();
1169
+ s.on("error", reject);
1170
+ s.listen(0, "::1", function () {
1171
+ var p = s.address().port;
1172
+ s.close(function () { resolve(p); });
1173
+ });
1174
+ });
1175
+ } catch (_e) { port = null; }
1176
+ if (port === null) {
1177
+ check("querySvcb(system): [::1]:port bracket parse (skipped — no IPv6 loopback)", true);
1178
+ _reset();
1179
+ return;
1180
+ }
1181
+ dnsModule.useSystemResolver();
1182
+ dnsModule.setServers(["[::1]:" + port]);
1183
+ dnsModule.setLookupTimeoutMs(2000);
1184
+ // Nothing listening on that ::1 port → connect refused → system-failed,
1185
+ // but the bracket-parse branch runs on the way there.
1186
+ check("querySvcb(system): [::1]:port bracket address parsed (refused → DnsError)",
1187
+ await _throwsAsync(function () {
1188
+ return dnsModule.querySvcb("example.com", { transport: "system" });
1189
+ }));
1190
+ await _drainTcpHandles();
1191
+ }
1192
+
1193
+ // ======================================================================
1194
+ // discoverEncrypted — mapping + no-transport + alias-skip branches
1195
+ // ======================================================================
1196
+ async function testDiscoverEncryptedBranches() {
1197
+ // name must be a string.
1198
+ _reset();
1199
+ check("discoverEncrypted: non-string name throws dns/bad-host",
1200
+ await _throwsAsync(function () { return dnsModule.discoverEncrypted({ name: 12345 }); }, "dns/bad-host"));
1201
+
1202
+ // NXDOMAIN (rcode 3) upstream → mapped to dns/ddr-not-discovered.
1203
+ _reset();
1204
+ var nx = _buildReply("_dns.resolver.arpa", 64, [], 0x8183);
1205
+ var nxFix = await _startTcpResponder(nx);
1206
+ dnsModule.useSystemResolver();
1207
+ dnsModule.setServers(["127.0.0.1:" + nxFix.port]);
1208
+ dnsModule.setLookupTimeoutMs(5000);
1209
+ check("discoverEncrypted: NXDOMAIN mapped to dns/ddr-not-discovered",
1210
+ await _throwsAsync(function () { return dnsModule.discoverEncrypted(); }, "dns/ddr-not-discovered"));
1211
+ nxFix.srv.close();
1212
+ await _drainTcpHandles();
1213
+
1214
+ // Only an AliasMode (priority 0) record present → all skipped → not-discovered.
1215
+ _reset();
1216
+ var aliasOnly = _buildReply("_dns.resolver.arpa", 64, [{
1217
+ name: "_dns.resolver.arpa", type: 64, rdata: _svcbRd(0, "alias.example.net", []),
1218
+ }]);
1219
+ var aliasFix = await _startTcpResponder(aliasOnly);
1220
+ dnsModule.useSystemResolver();
1221
+ dnsModule.setServers(["127.0.0.1:" + aliasFix.port]);
1222
+ dnsModule.setLookupTimeoutMs(5000);
1223
+ check("discoverEncrypted: alias-only records skipped → dns/ddr-not-discovered",
1224
+ await _throwsAsync(function () { return dnsModule.discoverEncrypted(); }, "dns/ddr-not-discovered"));
1225
+ aliasFix.srv.close();
1226
+ await _drainTcpHandles();
1227
+
1228
+ // ServiceMode with an unrecognized alpn (no dot/h2/h3, no dohpath) → skipped.
1229
+ _reset();
1230
+ var noTransport = _buildReply("_dns.resolver.arpa", 64, [{
1231
+ name: "_dns.resolver.arpa", type: 64,
1232
+ rdata: _svcbRd(1, "svc.example.net", [{ key: 1, value: _alpn(["ftp"]) }]),
1233
+ }]);
1234
+ var ntFix = await _startTcpResponder(noTransport);
1235
+ dnsModule.useSystemResolver();
1236
+ dnsModule.setServers(["127.0.0.1:" + ntFix.port]);
1237
+ dnsModule.setLookupTimeoutMs(5000);
1238
+ check("discoverEncrypted: no recognized transport → dns/ddr-not-discovered",
1239
+ await _throwsAsync(function () { return dnsModule.discoverEncrypted(); }, "dns/ddr-not-discovered"));
1240
+ ntFix.srv.close();
1241
+ await _drainTcpHandles();
1242
+
1243
+ // insecureSystemResolverOnly:false → transport auto (system here) still works.
1244
+ _reset();
1245
+ var good = _buildReply("_dns.resolver.arpa", 64, [{
1246
+ name: "_dns.resolver.arpa", type: 64,
1247
+ rdata: _svcbRd(1, "doh.example.net", [
1248
+ { key: 1, value: _alpn(["h2"]) },
1249
+ { key: 7, value: Buffer.from("/dns-query", "utf8") },
1250
+ ]),
1251
+ }]);
1252
+ var goodFix = await _startTcpResponder(good);
1253
+ dnsModule.useSystemResolver();
1254
+ dnsModule.setServers(["127.0.0.1:" + goodFix.port]);
1255
+ dnsModule.setLookupTimeoutMs(5000);
1256
+ var res = await dnsModule.discoverEncrypted({ insecureSystemResolverOnly: false });
1257
+ check("discoverEncrypted: insecureSystemResolverOnly:false auto transport returns a DoH descriptor",
1258
+ Array.isArray(res) && res.length === 1 && res[0].transport === "doh" && res[0].dohpath === "/dns-query");
1259
+ goodFix.srv.close();
1260
+ await _drainTcpHandles();
1261
+ }
1262
+
1263
+ // ======================================================================
1264
+ // useDesignatedResolvers — config-loop fallback branches
1265
+ // ======================================================================
1266
+ function testDesignatedResolversFallback() {
1267
+ // First entry passes pre-loop validation (https url) but fails to
1268
+ // configure (invalid method rejected by useDnsOverHttps) → caught,
1269
+ // second valid entry wins (active=1).
1270
+ _reset();
1271
+ var r = dnsModule.useDesignatedResolvers([
1272
+ { transport: "doh", url: "https://primary.example.net/dns-query", method: "PUT" },
1273
+ { transport: "doh", url: "https://secondary.example.net/dns-query" },
1274
+ ]);
1275
+ check("useDesignatedResolvers: first entry fails to configure → second wins (active=1)",
1276
+ r.active === 1 && r.count === 2 &&
1277
+ dnsModule._stateForTest().doh.url.indexOf("secondary") !== -1);
1278
+ _reset();
1279
+
1280
+ // Every entry fails to configure → dns/dnr-no-resolvers with last error.
1281
+ check("useDesignatedResolvers: all entries fail → dns/dnr-no-resolvers",
1282
+ _throws(function () {
1283
+ dnsModule.useDesignatedResolvers([
1284
+ { transport: "doh", url: "https://only.example.net/dns-query", method: "PATCH" },
1285
+ ]);
1286
+ }, "dns/dnr-no-resolvers"));
1287
+ _reset();
1288
+
1289
+ // A dot entry that passes host validation but fails port validation in
1290
+ // useDnsOverTls → caught → dnr-no-resolvers.
1291
+ check("useDesignatedResolvers: dot entry bad port → dnr-no-resolvers",
1292
+ _throws(function () {
1293
+ dnsModule.useDesignatedResolvers([
1294
+ { transport: "dot", host: "dot.example.net", port: -9 },
1295
+ ]);
1296
+ }, "dns/dnr-no-resolvers"));
1297
+ _reset();
1298
+ }
1299
+
1300
+ // ======================================================================
1301
+ // DoT success paths — real TLS 1.3 handshake against a loopback responder
1302
+ // (A / AAAA decode via _decodeDnsAnswer, _dotLookup, _dotRawQuery, the
1303
+ // lookup + _resolveProtocol DoT branches)
1304
+ // ======================================================================
1305
+ async function testDotSecureTransport() {
1306
+ var cert = await _mintSecureCert();
1307
+
1308
+ // ---- A-record lookup over DoT ----
1309
+ _reset();
1310
+ var aReply = _buildReply("secure.example.com", 1, [
1311
+ { name: "secure.example.com", type: 1, rdata: _aRdata(203, 0, 113, 5) },
1312
+ ]);
1313
+ var dotA = await _startDotServer(cert, { reply: aReply });
1314
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: dotA.port, servername: "localhost", ca: cert.caPem });
1315
+ dnsModule.setLookupTimeoutMs(5000);
1316
+ try {
1317
+ var a = await dnsModule.lookup("secure.example.com", { family: 4 });
1318
+ check("lookup(DoT): A record resolves via real TLS 1.3 handshake",
1319
+ a.address === "203.0.113.5" && a.family === 4);
1320
+ } finally { dotA.close(); await _drainTcpHandles(); }
1321
+
1322
+ // ---- AAAA-record resolve6 over DoT (_resolveProtocol DoT branch) ----
1323
+ _reset();
1324
+ var aaaaReply = _buildReply("v6.example.com", 28, [
1325
+ { name: "v6.example.com", type: 28, rdata: _aaaaRdata() },
1326
+ ]);
1327
+ var dotAAAA = await _startDotServer(cert, { reply: aaaaReply });
1328
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: dotAAAA.port, servername: "localhost", ca: cert.caPem });
1329
+ dnsModule.setLookupTimeoutMs(5000);
1330
+ try {
1331
+ var r6 = await dnsModule.resolve6("v6.example.com");
1332
+ check("resolve6(DoT): AAAA record decodes to an IPv6 string",
1333
+ Array.isArray(r6) && r6.length === 1 && r6[0].indexOf("2001:") === 0);
1334
+ } finally { dotAAAA.close(); await _drainTcpHandles(); }
1335
+
1336
+ // ---- SVCB query over DoT (_dotRawQuery raw path) ----
1337
+ _reset();
1338
+ var svcbReply = _buildReply("svc.example.com", 64, [
1339
+ { name: "svc.example.com", type: 64,
1340
+ rdata: _svcbRd(1, "target.example.net", [{ key: 1, value: _alpn(["h2"]) }]) },
1341
+ ]);
1342
+ var dotSvcb = await _startDotServer(cert, { reply: svcbReply });
1343
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: dotSvcb.port, servername: "localhost", ca: cert.caPem });
1344
+ dnsModule.setLookupTimeoutMs(5000);
1345
+ try {
1346
+ var svcb = await dnsModule.querySvcb("svc.example.com", { transport: "dot" });
1347
+ check("querySvcb(DoT): SVCB record parses over the TLS transport",
1348
+ Array.isArray(svcb) && svcb.length === 1 && svcb[0].params.alpn[0] === "h2");
1349
+ } finally { dotSvcb.close(); await _drainTcpHandles(); }
1350
+ }
1351
+
1352
+ // ======================================================================
1353
+ // DoH success paths — real HTTPS round-trip against a loopback responder
1354
+ // (_dohLookup GET + POST, _dohLookupSecure AD bit, _dohRawQuery, non-200)
1355
+ // ======================================================================
1356
+ async function testDohSecureTransport() {
1357
+ var cert = await _mintSecureCert();
1358
+ var aReply = _buildReply("doh.example.com", 1, [
1359
+ { name: "doh.example.com", type: 1, rdata: _aRdata(198, 51, 100, 9) },
1360
+ ]);
1361
+
1362
+ // ---- A lookup + resolve4 over DoH (GET) ----
1363
+ _reset();
1364
+ var dohA = await _startDohServer(cert, { reply: aReply });
1365
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + dohA.port + "/dns-query", ca: cert.caPem });
1366
+ dnsModule.setLookupTimeoutMs(5000);
1367
+ try {
1368
+ var a = await dnsModule.lookup("doh.example.com", { family: 4 });
1369
+ check("lookup(DoH GET): A record resolves over real HTTPS", a.address === "198.51.100.9");
1370
+ var r4 = await dnsModule.resolve4("doh.example.com");
1371
+ check("resolve4(DoH): A record via _resolveProtocol DoH branch",
1372
+ Array.isArray(r4) && r4[0] === "198.51.100.9");
1373
+ } finally { dohA.close(); await _drainTcpHandles(); }
1374
+
1375
+ // ---- POST method (usePost branch: content-type/length + req.write) ----
1376
+ _reset();
1377
+ var dohP = await _startDohServer(cert, { reply: aReply });
1378
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + dohP.port + "/dns-query", method: "POST", ca: cert.caPem });
1379
+ dnsModule.setLookupTimeoutMs(5000);
1380
+ try {
1381
+ var ap = await dnsModule.lookup("doh.example.com", { family: 4 });
1382
+ check("lookup(DoH POST): A record resolves via POST body", ap.address === "198.51.100.9");
1383
+ } finally { dohP.close(); await _drainTcpHandles(); }
1384
+
1385
+ // ---- resolveSecure over DoH with the AD bit set (_dohLookupSecure) ----
1386
+ _reset();
1387
+ var adReply = _buildReply("secure.example.com", 1, [
1388
+ { name: "secure.example.com", type: 1, rdata: _aRdata(203, 0, 113, 1) },
1389
+ ]);
1390
+ adReply.writeUInt16BE(0x81a0, 2); // flags: response + RA + AD bit (0x20 in byte 3)
1391
+ var dohSec = await _startDohServer(cert, { reply: adReply });
1392
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + dohSec.port + "/dns-query", ca: cert.caPem });
1393
+ dnsModule.setLookupTimeoutMs(5000);
1394
+ try {
1395
+ var sec = await dnsModule.resolveSecure("secure.example.com", "A");
1396
+ check("resolveSecure(DoH): returns { rrs, ad } with the AD bit surfaced",
1397
+ sec && Array.isArray(sec.rrs) && sec.rrs[0] === "203.0.113.1" && sec.ad === true);
1398
+ } finally { dohSec.close(); await _drainTcpHandles(); }
1399
+
1400
+ // ---- SVCB over DoH (_dohRawQuery raw path) ----
1401
+ _reset();
1402
+ var svcbReply = _buildReply("svc.example.com", 64, [
1403
+ { name: "svc.example.com", type: 64,
1404
+ rdata: _svcbRd(1, "t.example.net", [{ key: 1, value: _alpn(["h3"]) }]) },
1405
+ ]);
1406
+ var dohSvcb = await _startDohServer(cert, { reply: svcbReply });
1407
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + dohSvcb.port + "/dns-query", ca: cert.caPem });
1408
+ dnsModule.setLookupTimeoutMs(5000);
1409
+ try {
1410
+ var svcb = await dnsModule.querySvcb("svc.example.com", { transport: "doh" });
1411
+ check("querySvcb(DoH): SVCB record parses over HTTPS",
1412
+ Array.isArray(svcb) && svcb.length === 1 && svcb[0].params.alpn[0] === "h3");
1413
+ } finally { dohSvcb.close(); await _drainTcpHandles(); }
1414
+
1415
+ // ---- DoH non-200 status → dns/doh-http ----
1416
+ _reset();
1417
+ var doh500 = await _startDohServer(cert, { reply: Buffer.alloc(0), status: 500 });
1418
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + doh500.port + "/dns-query", ca: cert.caPem });
1419
+ dnsModule.setLookupTimeoutMs(5000);
1420
+ try {
1421
+ check("querySvcb(DoH 500): non-200 response surfaces dns/doh-http",
1422
+ await _throwsAsync(function () {
1423
+ return dnsModule.querySvcb("svc.example.com", { transport: "doh" });
1424
+ }, "dns/doh-http"));
1425
+ } finally { doh500.close(); await _drainTcpHandles(); }
1426
+ }
1427
+
1428
+ // ======================================================================
1429
+ // Secure-transport wall-clock deadlines — a stalled upstream must be torn
1430
+ // down (_armRequestTimeout for DoH, _dotConnect sock.setTimeout for DoT,
1431
+ // and the shared _withTimeout deadline)
1432
+ // ======================================================================
1433
+ async function testSecureTransportTimeouts() {
1434
+ var cert = await _mintSecureCert();
1435
+
1436
+ // ---- DoH request accepted then stalled → dns/lookup-timeout ----
1437
+ _reset();
1438
+ var dohHang = await _startDohServer(cert, { hang: true });
1439
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + dohHang.port + "/dns-query", ca: cert.caPem });
1440
+ dnsModule.setLookupTimeoutMs(700);
1441
+ try {
1442
+ check("querySvcb(DoH stalled): request deadline surfaces dns/lookup-timeout",
1443
+ await _throwsAsync(function () {
1444
+ return dnsModule.querySvcb("svc.example.com", { transport: "doh" });
1445
+ }, "dns/lookup-timeout"));
1446
+ // The promise-level deadline can win the race with the socket-level
1447
+ // req.setTimeout; give the request-teardown callback a window to fire
1448
+ // before the fixture is destroyed (verifies no lingering handle).
1449
+ await helpers.passiveObserve(400, "network-dns: DoH request-teardown grace");
1450
+ } finally { dohHang.close(); await _drainTcpHandles(); }
1451
+
1452
+ // ---- DoT handshake completes, query stalls → socket deadline tears down ----
1453
+ _reset();
1454
+ var dotHang = await _startDotServer(cert, { hang: true });
1455
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: dotHang.port, servername: "localhost", ca: cert.caPem });
1456
+ dnsModule.setLookupTimeoutMs(700);
1457
+ try {
1458
+ check("resolve4(DoT stalled): idle socket deadline surfaces a DnsError",
1459
+ await _throwsAsync(function () { return dnsModule.resolve4("hang.example.com"); }));
1460
+ await helpers.passiveObserve(400, "network-dns: DoT socket-teardown grace");
1461
+ } finally { dotHang.close(); await _drainTcpHandles(); }
1462
+ }
1463
+
1464
+ // ======================================================================
1465
+ // Remaining defensive / adversarial / option-default branches reachable
1466
+ // wholly in-process (local-form normalization, env transport override,
1467
+ // LDH label rejection, DNR entry shape, DDR non-NXDOMAIN rethrow, raw name
1468
+ // decode limits, transport-unavailable + no-resolvers guards, system
1469
+ // timeout, native-error wraps)
1470
+ // ======================================================================
1471
+ async function testLocalFormTrailingDot() {
1472
+ _reset();
1473
+ dnsModule.setLookupTimeoutMs(4000);
1474
+ try {
1475
+ var ld = await dnsModule.lookup("localhost.");
1476
+ check("lookup: fully-qualified 'localhost.' strips the root dot → system path",
1477
+ typeof ld.address === "string" && (ld.family === 4 || ld.family === 6));
1478
+ // explicit family over the system resolver → sets nodeOpts.family
1479
+ var ld4 = await dnsModule.lookup("localhost", { family: 4 });
1480
+ check("lookup(system, family:4): pins the address family on the OS resolver",
1481
+ ld4.family === 4);
1482
+ } finally { _reset(); }
1483
+ }
1484
+
1485
+ async function testEnsureSecureDefaultEnvOverride() {
1486
+ var saved = process.env.BLAMEJS_DNS_TRANSPORT;
1487
+ try {
1488
+ // BLAMEJS_DNS_TRANSPORT=system → the default resolver is the OS resolver.
1489
+ process.env.BLAMEJS_DNS_TRANSPORT = "system";
1490
+ _reset();
1491
+ dnsModule.setLookupTimeoutMs(4000);
1492
+ await dnsModule.lookup("localhost");
1493
+ check("lookup: BLAMEJS_DNS_TRANSPORT=system arms the system resolver default",
1494
+ dnsModule._stateForTest().systemResolver === true);
1495
+
1496
+ // BLAMEJS_DNS_TRANSPORT=dot → default DoT config is armed; a local-form
1497
+ // host short-circuits to the system path so no external connection runs.
1498
+ process.env.BLAMEJS_DNS_TRANSPORT = "dot";
1499
+ _reset();
1500
+ dnsModule.setLookupTimeoutMs(4000);
1501
+ await dnsModule.lookup("localhost");
1502
+ var dotState = dnsModule._stateForTest().dot;
1503
+ check("lookup: BLAMEJS_DNS_TRANSPORT=dot arms the default DoT config (port 853)",
1504
+ dotState && dotState.host === "1.1.1.1" && dotState.port === 853);
1505
+ } finally {
1506
+ if (saved === undefined) delete process.env.BLAMEJS_DNS_TRANSPORT;
1507
+ else process.env.BLAMEJS_DNS_TRANSPORT = saved;
1508
+ _reset();
1509
+ }
1510
+ }
1511
+
1512
+ async function testValidateLdhLabelReject() {
1513
+ _reset();
1514
+ check("querySvcb: label with a non-LDH character throws dns/bad-host",
1515
+ await _throwsAsync(function () {
1516
+ return dnsModule.querySvcb("bad!char.example.com", { transport: "system" });
1517
+ }, "dns/bad-host"));
1518
+ _reset();
1519
+ }
1520
+
1521
+ function testDesignatedResolversNonObjectEntry() {
1522
+ _reset();
1523
+ check("useDesignatedResolvers: non-object entry throws dns/dnr-malformed",
1524
+ _throws(function () { dnsModule.useDesignatedResolvers([42]); }, "dns/dnr-malformed"));
1525
+ _reset();
1526
+ }
1527
+
1528
+ async function testDiscoverEncryptedRethrow() {
1529
+ // A transport failure that is NOT rcode/NXDOMAIN must be rethrown as-is
1530
+ // (only a genuine no-result maps to dns/ddr-not-discovered).
1531
+ _reset();
1532
+ var refused = await _probeClosedPort();
1533
+ dnsModule.useSystemResolver();
1534
+ dnsModule.setServers(["127.0.0.1:" + refused]);
1535
+ dnsModule.setLookupTimeoutMs(2500);
1536
+ try {
1537
+ check("discoverEncrypted: connection failure (not NXDOMAIN) is rethrown unchanged",
1538
+ await _throwsAsync(function () { return dnsModule.discoverEncrypted(); }, "dns/system-failed"));
1539
+ } finally { await _drainTcpHandles(); }
1540
+ }
1541
+
1542
+ function testReadDnsNameLimits() {
1543
+ var rdn = dnsModule._readDnsName;
1544
+ // Label length runs past the end of the message.
1545
+ check("_readDnsName: label length exceeding the message throws dns/svcb-malformed",
1546
+ _throws(function () { return rdn(Buffer.from([5, 0x61]), 0); }, "dns/svcb-malformed"));
1547
+ // A run of single-byte labels with no terminator, longer than the
1548
+ // 256-hop compression-loop cap → hits the iteration guard before the
1549
+ // not-terminated guard.
1550
+ var longLabels = Buffer.alloc(600);
1551
+ for (var i = 0; i < 600; i += 2) { longLabels[i] = 1; longLabels[i + 1] = 0x61; }
1552
+ check("_readDnsName: label walk beyond the 256-hop cap throws dns/svcb-malformed",
1553
+ _throws(function () { return rdn(longLabels, 0); }, "dns/svcb-malformed"));
1554
+ }
1555
+
1556
+ async function testRawQueryTransportUnavailable() {
1557
+ // System-only config, then a forced doh/dot transport with no matching
1558
+ // config → _rawQuery raises dns/transport-unavailable (permanent).
1559
+ _reset();
1560
+ dnsModule.useSystemResolver();
1561
+ check("querySvcb(transport:doh) under system-only config → dns/transport-unavailable",
1562
+ await _throwsAsync(function () {
1563
+ return dnsModule.querySvcb("example.com", { transport: "doh" });
1564
+ }, "dns/transport-unavailable"));
1565
+ check("querySvcb(transport:dot) under system-only config → dns/transport-unavailable",
1566
+ await _throwsAsync(function () {
1567
+ return dnsModule.querySvcb("example.com", { transport: "dot" });
1568
+ }, "dns/transport-unavailable"));
1569
+ _reset();
1570
+ }
1571
+
1572
+ async function testSystemRawQueryNoServers() {
1573
+ // Force getServers() to report zero configured resolvers.
1574
+ _reset();
1575
+ dnsModule.useSystemResolver();
1576
+ dnsModule._stateForTest().servers = [];
1577
+ try {
1578
+ check("querySvcb(system): zero configured resolvers → dns/no-system-resolvers",
1579
+ await _throwsAsync(function () {
1580
+ return dnsModule.querySvcb("example.com", { transport: "system" });
1581
+ }, "dns/no-system-resolvers"));
1582
+ } finally { _reset(); }
1583
+ }
1584
+
1585
+ async function testSystemRawQueryTimeout() {
1586
+ // Upstream accepts the TCP connection then stalls → sock.setTimeout
1587
+ // wall-clock deadline settles the query with dns/lookup-timeout.
1588
+ _reset();
1589
+ var hang = await _startTcpHang();
1590
+ dnsModule.useSystemResolver();
1591
+ dnsModule.setServers(["127.0.0.1:" + hang.port]);
1592
+ dnsModule.setLookupTimeoutMs(700);
1593
+ try {
1594
+ check("querySvcb(system): upstream accepts then stalls → dns/lookup-timeout",
1595
+ await _throwsAsync(function () {
1596
+ return dnsModule.querySvcb("example.com", { transport: "system" });
1597
+ }, "dns/lookup-timeout"));
1598
+ // The socket-level sock.setTimeout deadline can fire a hair after the
1599
+ // promise-level _withTimeout; let it settle before the fixture teardown.
1600
+ await helpers.passiveObserve(250, "network-dns: system socket-teardown grace");
1601
+ } finally { hang.close(); await _drainTcpHandles(); }
1602
+ }
1603
+
1604
+ async function testNativeErrorWraps() {
1605
+ // resolve4 over the system resolver with an unparseable host → c-ares
1606
+ // rejects with a native EBADNAME (no network); the framework wraps it as
1607
+ // dns/resolve-failed via the non-DnsError branch.
1608
+ _reset();
1609
+ dnsModule.useSystemResolver();
1610
+ dnsModule.setLookupTimeoutMs(5000);
1611
+ check("resolve4(system): native c-ares error wraps as dns/resolve-failed",
1612
+ await _throwsAsync(function () {
1613
+ return dnsModule.resolve4("bad host with spaces");
1614
+ }, "dns/resolve-failed"));
1615
+ _reset();
1616
+
1617
+ // reverse of a reserved IP → native ENOTFOUND (no network); wrapped as
1618
+ // dns/reverse-failed via the non-DnsError branch.
1619
+ dnsModule.useSystemResolver();
1620
+ dnsModule.setLookupTimeoutMs(5000);
1621
+ check("reverse: native c-ares error wraps as dns/reverse-failed (IPv4)",
1622
+ await _throwsAsync(function () { return dnsModule.reverse("0.0.0.0"); }, "dns/reverse-failed"));
1623
+ // An IPv6 literal exercises the family-6 branch of the reverse-requested
1624
+ // observability event.
1625
+ check("reverse: IPv6 literal native error wraps as dns/reverse-failed",
1626
+ await _throwsAsync(function () { return dnsModule.reverse("::"); }, "dns/reverse-failed"));
1627
+ _reset();
1628
+ }
1629
+
1630
+ // ======================================================================
1631
+ // DoT decode + adversarial-reply + auto-transport branches (real TLS)
1632
+ // ======================================================================
1633
+ async function testDotDecodeAndErrorBranches() {
1634
+ var cert = await _mintSecureCert();
1635
+
1636
+ // ---- answer owner name via compression pointer (_skipDnsName pointer) ----
1637
+ _reset();
1638
+ var comp = _buildReplyCompressedName("comp.example.com", 1, 1, _aRdata(192, 0, 2, 7));
1639
+ var s1 = await _startDotServer(cert, { reply: comp });
1640
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: s1.port, servername: "localhost", ca: cert.caPem });
1641
+ dnsModule.setLookupTimeoutMs(5000);
1642
+ try {
1643
+ var a = await dnsModule.lookup("comp.example.com", { family: 4 });
1644
+ check("lookup(DoT): compressed answer name decodes (name-compression branch)",
1645
+ a.address === "192.0.2.7");
1646
+ } finally { s1.close(); await _drainTcpHandles(); }
1647
+
1648
+ // ---- SERVFAIL rcode over DoT → decode raises dns/no-result ----
1649
+ _reset();
1650
+ var servfail = _buildReply("sf.example.com", 1,
1651
+ [{ name: "sf.example.com", type: 1, rdata: _aRdata(1, 2, 3, 4) }], 0x8182); // rcode 2 = SERVFAIL
1652
+ var s2 = await _startDotServer(cert, { reply: servfail });
1653
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: s2.port, servername: "localhost", ca: cert.caPem });
1654
+ dnsModule.setLookupTimeoutMs(5000);
1655
+ try {
1656
+ check("resolve4(DoT): SERVFAIL rcode surfaces a DnsError (decode reject path)",
1657
+ await _throwsAsync(function () { return dnsModule.resolve4("sf.example.com"); }));
1658
+ } finally { s2.close(); await _drainTcpHandles(); }
1659
+
1660
+ // ---- truncated rdata over DoT → decode raises dns/bad-reply ----
1661
+ _reset();
1662
+ var trunc = _buildReply("tr.example.com", 1,
1663
+ [{ name: "tr.example.com", type: 1, rdata: _aRdata(9, 9, 9, 9) }]);
1664
+ trunc.writeUInt16BE(0x00ff, trunc.length - 6); // rdlen lies past buffer end
1665
+ var s3 = await _startDotServer(cert, { reply: trunc });
1666
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: s3.port, servername: "localhost", ca: cert.caPem });
1667
+ dnsModule.setLookupTimeoutMs(5000);
1668
+ try {
1669
+ check("resolve4(DoT): truncated rdata surfaces a DnsError (decode reject path)",
1670
+ await _throwsAsync(function () { return dnsModule.resolve4("tr.example.com"); }));
1671
+ } finally { s3.close(); await _drainTcpHandles(); }
1672
+
1673
+ // ---- querySvcb with NO opts → auto-selects the configured DoT transport ----
1674
+ _reset();
1675
+ var svcbReply = _buildReply("auto.example.com", 64, [{ name: "auto.example.com", type: 64,
1676
+ rdata: _svcbRd(1, "t.example.net", [{ key: 1, value: _alpn(["h2"]) }]) }]);
1677
+ var s5 = await _startDotServer(cert, { reply: svcbReply });
1678
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: s5.port, servername: "localhost", ca: cert.caPem });
1679
+ dnsModule.setLookupTimeoutMs(5000);
1680
+ try {
1681
+ var svcb = await dnsModule.querySvcb("auto.example.com"); // no opts → _rawQuery auto-selects DoT
1682
+ check("querySvcb(auto): no transport opt auto-selects the configured DoT",
1683
+ Array.isArray(svcb) && svcb.length === 1 && svcb[0].params.alpn[0] === "h2");
1684
+ } finally { s5.close(); await _drainTcpHandles(); }
1685
+
1686
+ // ---- SVCB reply carrying a non-matching answer type → skipped ----
1687
+ _reset();
1688
+ var mixed = _buildReply("mix.example.com", 64, [
1689
+ { name: "mix.example.com", type: 1, rdata: _aRdata(10, 0, 0, 1) }, // A record — must be skipped
1690
+ { name: "mix.example.com", type: 64, rdata: _svcbRd(1, "t.example.net", [{ key: 1, value: _alpn(["h3"]) }]) },
1691
+ ]);
1692
+ var s6 = await _startDotServer(cert, { reply: mixed });
1693
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: s6.port, servername: "localhost", ca: cert.caPem });
1694
+ dnsModule.setLookupTimeoutMs(5000);
1695
+ try {
1696
+ var mr = await dnsModule.querySvcb("mix.example.com", { transport: "dot" });
1697
+ check("querySvcb(DoT): a non-SVCB answer record is filtered out",
1698
+ Array.isArray(mr) && mr.length === 1 && mr[0].params.alpn[0] === "h3");
1699
+ } finally { s6.close(); await _drainTcpHandles(); }
1700
+
1701
+ // ---- reply shorter than a DNS header → decode rejects (buf < 12) ----
1702
+ _reset();
1703
+ var s7 = await _startDotServer(cert, { reply: Buffer.alloc(6) });
1704
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: s7.port, servername: "localhost", ca: cert.caPem });
1705
+ dnsModule.setLookupTimeoutMs(5000);
1706
+ try {
1707
+ check("resolve4(DoT): sub-header reply surfaces a DnsError (buf<12 guard)",
1708
+ await _throwsAsync(function () { return dnsModule.resolve4("short.example.com"); }));
1709
+ } finally { s7.close(); await _drainTcpHandles(); }
1710
+
1711
+ // ---- ancount lies (claims an answer, none present) → record-header truncated ----
1712
+ _reset();
1713
+ var lie = _buildReply("lie.example.com", 1, []);
1714
+ lie.writeUInt16BE(1, 6); // ANCOUNT = 1, but no answer bytes
1715
+ var s8 = await _startDotServer(cert, { reply: lie });
1716
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: s8.port, servername: "localhost", ca: cert.caPem });
1717
+ dnsModule.setLookupTimeoutMs(5000);
1718
+ try {
1719
+ check("resolve4(DoT): lying ANCOUNT surfaces a DnsError (record-header guard)",
1720
+ await _throwsAsync(function () { return dnsModule.resolve4("lie.example.com"); }));
1721
+ } finally { s8.close(); await _drainTcpHandles(); }
1722
+
1723
+ // ---- NOERROR reply with zero answers → resolve raises dns/no-result ----
1724
+ _reset();
1725
+ var empty = _buildReply("empty.example.com", 1, []); // ANCOUNT 0, NOERROR
1726
+ var s9 = await _startDotServer(cert, { reply: empty });
1727
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: s9.port, servername: "localhost", ca: cert.caPem });
1728
+ dnsModule.setLookupTimeoutMs(5000);
1729
+ try {
1730
+ check("resolve6(DoT): NOERROR with no matching answers → dns/no-result",
1731
+ await _throwsAsync(function () { return dnsModule.resolve6("empty.example.com"); }, "dns/no-result"));
1732
+ } finally { s9.close(); await _drainTcpHandles(); }
1733
+ }
1734
+
1735
+ // ======================================================================
1736
+ // DoH GET-with-query, POST-secure/raw, non-200 for lookup + resolveSecure,
1737
+ // and family-0 dual-stack ordering (real HTTPS)
1738
+ // ======================================================================
1739
+ async function testDohDecodeAndErrorBranches() {
1740
+ var cert = await _mintSecureCert();
1741
+ var aReply = _buildReply("doh2.example.com", 1,
1742
+ [{ name: "doh2.example.com", type: 1, rdata: _aRdata(198, 51, 100, 42) }]);
1743
+
1744
+ // ---- DoH url already carrying a query string → getUrl joins with '&' ----
1745
+ _reset();
1746
+ var qsrv = await _startDohServer(cert, { reply: aReply });
1747
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + qsrv.port + "/dns-query?ns=1", ca: cert.caPem });
1748
+ dnsModule.setLookupTimeoutMs(5000);
1749
+ try {
1750
+ var a = await dnsModule.lookup("doh2.example.com", { family: 4 });
1751
+ check("lookup(DoH, url with existing query): appends the dns param with '&'",
1752
+ a.address === "198.51.100.42");
1753
+ } finally { qsrv.close(); await _drainTcpHandles(); }
1754
+
1755
+ // ---- resolveSecure over DoH via POST + '?'-url (usePost + '&' branches) ----
1756
+ _reset();
1757
+ var adReply = _buildReply("sec.example.com", 1,
1758
+ [{ name: "sec.example.com", type: 1, rdata: _aRdata(203, 0, 113, 9) }]);
1759
+ adReply.writeUInt16BE(0x81a0, 2); // AD bit set
1760
+ var psec = await _startDohServer(cert, { reply: adReply });
1761
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + psec.port + "/dns-query?p=1", method: "POST", ca: cert.caPem });
1762
+ dnsModule.setLookupTimeoutMs(5000);
1763
+ try {
1764
+ var sec = await dnsModule.resolveSecure("sec.example.com", "A");
1765
+ check("resolveSecure(DoH POST, ?-url): decodes via POST body over the '&' getUrl branch",
1766
+ sec && Array.isArray(sec.rrs) && sec.rrs[0] === "203.0.113.9" && sec.ad === true);
1767
+ } finally { psec.close(); await _drainTcpHandles(); }
1768
+
1769
+ // ---- querySvcb over DoH via POST + auto transport (raw usePost branch) ----
1770
+ _reset();
1771
+ var svcbReply = _buildReply("praw.example.com", 64, [{ name: "praw.example.com", type: 64,
1772
+ rdata: _svcbRd(1, "t.example.net", [{ key: 1, value: _alpn(["h2"]) }]) }]);
1773
+ var praw = await _startDohServer(cert, { reply: svcbReply });
1774
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + praw.port + "/dns-query?p=1", method: "POST", ca: cert.caPem });
1775
+ dnsModule.setLookupTimeoutMs(5000);
1776
+ try {
1777
+ var svcb = await dnsModule.querySvcb("praw.example.com"); // no transport → auto DoH, POST body
1778
+ check("querySvcb(DoH POST, auto transport): raw query round-trips via POST body",
1779
+ Array.isArray(svcb) && svcb.length === 1 && svcb[0].params.alpn[0] === "h2");
1780
+ } finally { praw.close(); await _drainTcpHandles(); }
1781
+
1782
+ // ---- non-200 for lookup (_dohLookup) + resolveSecure (_dohLookupSecure) ----
1783
+ _reset();
1784
+ var e500 = await _startDohServer(cert, { reply: Buffer.alloc(0), status: 500 });
1785
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + e500.port + "/dns-query", ca: cert.caPem });
1786
+ dnsModule.setLookupTimeoutMs(5000);
1787
+ try {
1788
+ check("lookup(DoH 500, family:4): _dohLookup non-200 surfaces dns/doh-http",
1789
+ await _throwsAsync(function () {
1790
+ return dnsModule.lookup("x.example.com", { family: 4 });
1791
+ }, "dns/doh-http"));
1792
+ check("resolveSecure(DoH 500): _dohLookupSecure non-200 surfaces dns/doh-http",
1793
+ await _throwsAsync(function () {
1794
+ return dnsModule.resolveSecure("x.example.com", "A");
1795
+ }, "dns/doh-http"));
1796
+ } finally { e500.close(); await _drainTcpHandles(); }
1797
+
1798
+ // ---- family-0 dual-stack over DoH with ipv6first ordering ----
1799
+ _reset();
1800
+ var dsrv = await _startDohServer(cert, { reply: aReply });
1801
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + dsrv.port + "/dns-query", ca: cert.caPem });
1802
+ dnsModule.setResultOrder("ipv6first");
1803
+ dnsModule.setLookupTimeoutMs(5000);
1804
+ try {
1805
+ var all = await dnsModule.lookup("doh2.example.com", { all: true }); // family 0 → _dualStack both families
1806
+ check("lookup(DoH, family 0, ipv6first): dual-stack returns the A answer",
1807
+ Array.isArray(all) && all.length >= 1 && all[0].address === "198.51.100.42");
1808
+ } finally { dsrv.close(); await _drainTcpHandles(); }
1809
+ }
1810
+
1811
+ async function testResolveTypeAndNodeLookupBranches() {
1812
+ // resolve(): a non-string type is rejected as a typed DnsError (not a
1813
+ // raw TypeError from .toUpperCase()).
1814
+ _reset();
1815
+ check("resolve: non-string type throws dns/unsupported-type",
1816
+ await _throwsAsync(function () { return dnsModule.resolve("192.0.2.1", 123); }, "dns/unsupported-type"));
1817
+ // Omitted type defaults to 'A' (the `type || "A"` branch) and short-circuits
1818
+ // on the IP literal offline.
1819
+ var a = await dnsModule.resolve("192.0.2.1");
1820
+ check("resolve: omitted type defaults to A + short-circuits the IP literal",
1821
+ Array.isArray(a) && a[0] === "192.0.2.1");
1822
+ _reset();
1823
+
1824
+ // nodeLookup(): explicit null options falls back to {} (the `options || {}`
1825
+ // branch); an explicit family flows through to lookup().
1826
+ var nullOpts = await _nodeLookupP("192.0.2.60", null);
1827
+ check("nodeLookup: explicit null options defaults to {} → (address, family)",
1828
+ nullOpts[0] === "192.0.2.60" && nullOpts[1] === 4);
1829
+ var famOpts = await _nodeLookupP("192.0.2.61", { family: 4 });
1830
+ check("nodeLookup: explicit family flows through to lookup()",
1831
+ famOpts[0] === "192.0.2.61" && famOpts[1] === 4);
1832
+ _reset();
1833
+ }
1834
+
1835
+ // ======================================================================
1836
+ // Additional transport branches: DoH malformed-200 decode-in-end-handler,
1837
+ // DoT-raw handshake failure, system close-before-reply, no-arg config
1838
+ // throws, and the deadline-disabled (ms=0) path
1839
+ // ======================================================================
1840
+ async function testMoreTransportBranches() {
1841
+ var cert = await _mintSecureCert();
1842
+
1843
+ // ---- config setters with NO opts → default {} then required-field throw ----
1844
+ _reset();
1845
+ check("useDnsOverHttps(): no opts defaults to {} then throws dns/bad-doh-url",
1846
+ _throws(function () { dnsModule.useDnsOverHttps(); }, "dns/bad-doh-url"));
1847
+ check("useDnsOverTls(): no opts defaults to {} then throws dns/bad-dot-host",
1848
+ _throws(function () { dnsModule.useDnsOverTls(); }, "dns/bad-dot-host"));
1849
+ _reset();
1850
+
1851
+ // ---- DoH 200 with a malformed body → decode throws inside the end handler ----
1852
+ // Drives the catch(e){reject(e)} arm of _dohLookup / _dohLookupSecure /
1853
+ // _dohRawQuery (a 200 response whose body fails to decode).
1854
+ _reset();
1855
+ var badBody = _buildReply("bad.example.com", 1,
1856
+ [{ name: "bad.example.com", type: 1, rdata: _aRdata(9, 9, 9, 9) }]);
1857
+ badBody.writeUInt16BE(0x00ff, badBody.length - 6); // rdlen lies past end
1858
+ var mErr = await _startDohServer(cert, { reply: badBody });
1859
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + mErr.port + "/dns-query", ca: cert.caPem });
1860
+ dnsModule.setLookupTimeoutMs(5000);
1861
+ try {
1862
+ check("resolve4(DoH): malformed 200 body surfaces a DnsError (_dohLookup end-handler)",
1863
+ await _throwsAsync(function () { return dnsModule.resolve4("bad.example.com"); }));
1864
+ check("resolveSecure(DoH): malformed 200 body surfaces a DnsError (_dohLookupSecure)",
1865
+ await _throwsAsync(function () { return dnsModule.resolveSecure("bad.example.com", "A"); }));
1866
+ check("querySvcb(DoH): malformed 200 body surfaces a DnsError (_dohRawQuery)",
1867
+ await _throwsAsync(function () { return dnsModule.querySvcb("bad.example.com", { transport: "doh" }); }));
1868
+ } finally { mErr.close(); await _drainTcpHandles(); }
1869
+
1870
+ // ---- querySvcb(DoT) against a closed port → _dotRawQuery handshake failure ----
1871
+ _reset();
1872
+ var closed = await _probeClosedPort();
1873
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: closed, servername: "localhost", ca: cert.caPem });
1874
+ dnsModule.setLookupTimeoutMs(2000);
1875
+ try {
1876
+ check("querySvcb(DoT, dead upstream): raw-query handshake failure surfaces a DnsError",
1877
+ await _throwsAsync(function () { return dnsModule.querySvcb("svc.example.com", { transport: "dot" }); }));
1878
+ } finally { await _drainTcpHandles(); }
1879
+
1880
+ // ---- system transport: upstream FINs after the query, no reply ----
1881
+ _reset();
1882
+ var fin = await _startTcpFinNoReply();
1883
+ dnsModule.useSystemResolver();
1884
+ dnsModule.setServers(["127.0.0.1:" + fin.port]);
1885
+ dnsModule.setLookupTimeoutMs(5000);
1886
+ try {
1887
+ check("querySvcb(system): upstream closes before replying → dns/system-failed",
1888
+ await _throwsAsync(function () {
1889
+ return dnsModule.querySvcb("example.com", { transport: "system" });
1890
+ }, "dns/system-failed"));
1891
+ } finally { fin.close(); await _drainTcpHandles(); }
1892
+
1893
+ // ---- deadline disabled (lookupTimeoutMs === 0) over a healthy DoH upstream ----
1894
+ // Exercises the ms<=0 short-circuits in _withTimeout + _armRequestTimeout.
1895
+ _reset();
1896
+ var okReply = _buildReply("ok.example.com", 1,
1897
+ [{ name: "ok.example.com", type: 1, rdata: _aRdata(192, 0, 2, 200) }]);
1898
+ var okSrv = await _startDohServer(cert, { reply: okReply });
1899
+ dnsModule.useDnsOverHttps({ url: "https://127.0.0.1:" + okSrv.port + "/dns-query", ca: cert.caPem });
1900
+ dnsModule.setLookupTimeoutMs(0);
1901
+ try {
1902
+ var a = await dnsModule.lookup("ok.example.com", { family: 4 });
1903
+ check("lookup(DoH, timeout disabled): resolves without arming a deadline",
1904
+ a.address === "192.0.2.200");
1905
+ } finally { okSrv.close(); await _drainTcpHandles(); }
1906
+
1907
+ // ---- deadline disabled over a healthy DoT upstream (_dotConnect skips setTimeout) ----
1908
+ _reset();
1909
+ var okDot = await _startDotServer(cert, { reply: okReply });
1910
+ dnsModule.useDnsOverTls({ host: "127.0.0.1", port: okDot.port, servername: "localhost", ca: cert.caPem });
1911
+ dnsModule.setLookupTimeoutMs(0);
1912
+ try {
1913
+ var d = await dnsModule.resolve4("ok.example.com");
1914
+ check("resolve4(DoT, timeout disabled): resolves without arming a socket deadline",
1915
+ Array.isArray(d) && d[0] === "192.0.2.200");
1916
+ } finally { okDot.close(); await _drainTcpHandles(); }
1917
+ }
1918
+
254
1919
  async function run() {
255
1920
  try { await _runTests(); }
256
1921
  finally { await _drainTcpHandles(); }
@@ -676,6 +2341,67 @@ async function _runTests() {
676
2341
  reservedBuf[12] = 0x80;
677
2342
  check("_readDnsName: reserved label type throws dns/svcb-malformed",
678
2343
  _throws(function () { rd(reservedBuf, 12); }, "dns/svcb-malformed"));
2344
+
2345
+ // ============================================================
2346
+ // Public-surface error / defensive / adversarial branches —
2347
+ // config setters, classifiers, parse + decode faults, lookup
2348
+ // cache paths, and transport fault injection
2349
+ // ============================================================
2350
+
2351
+ // sync config + classifier + parse branches
2352
+ testSetServers();
2353
+ testSetResultOrder();
2354
+ testSetFamily();
2355
+ testSetLookupTimeout();
2356
+ testSetCacheTtl();
2357
+ testUseDnsOverHttps();
2358
+ testUseDnsOverTls();
2359
+ testUseSystemResolver();
2360
+ testIsNullMx();
2361
+ testClassifyDnskeyAlgorithm();
2362
+ testClassifyDsDigestType();
2363
+ testParseSvcbMalformed();
2364
+ testParseSvcbValidVariants();
2365
+ testDecodeAnswerRaw();
2366
+ testReadDnsName();
2367
+ testDesignatedResolversFallback();
2368
+
2369
+ // async / transport branches
2370
+ await testLookupIpLiteral();
2371
+ await testLookupLocalFormAndCache();
2372
+ await testLookupNegativeCache();
2373
+ await testLookupOrderingBranches();
2374
+ await testLookupDohDotNoResult();
2375
+ await testResolveProtocol();
2376
+ await testResolveTransportErrors();
2377
+ await testResolveDispatch();
2378
+ await testResolveSecure();
2379
+ await testReverse();
2380
+ await testNodeLookup();
2381
+ await testSystemRawQueryErrors();
2382
+ await testSystemRawQueryV6Bracket();
2383
+ await testDiscoverEncryptedBranches();
2384
+
2385
+ // real-handshake DoT / DoH transport round-trips + deadlines
2386
+ await testDotSecureTransport();
2387
+ await testDohSecureTransport();
2388
+ await testDotDecodeAndErrorBranches();
2389
+ await testDohDecodeAndErrorBranches();
2390
+ await testSecureTransportTimeouts();
2391
+
2392
+ // remaining in-process defensive / adversarial / option-default branches
2393
+ await testLocalFormTrailingDot();
2394
+ await testEnsureSecureDefaultEnvOverride();
2395
+ await testValidateLdhLabelReject();
2396
+ testDesignatedResolversNonObjectEntry();
2397
+ await testDiscoverEncryptedRethrow();
2398
+ testReadDnsNameLimits();
2399
+ await testRawQueryTransportUnavailable();
2400
+ await testSystemRawQueryNoServers();
2401
+ await testSystemRawQueryTimeout();
2402
+ await testNativeErrorWraps();
2403
+ await testResolveTypeAndNodeLookupBranches();
2404
+ await testMoreTransportBranches();
679
2405
  }
680
2406
 
681
2407
  module.exports = { run: run };