@blamejs/blamejs-shop 0.5.12 → 0.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (521) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +632 -416
  4. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
  5. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
  6. package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
  7. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  8. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
  9. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
  10. package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
  11. package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
  12. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
  13. package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
  14. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
  15. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  16. package/lib/vendor/blamejs/.gitignore +2 -0
  17. package/lib/vendor/blamejs/CHANGELOG.md +122 -0
  18. package/lib/vendor/blamejs/NOTICE +26 -1
  19. package/lib/vendor/blamejs/SECURITY.md +1 -1
  20. package/lib/vendor/blamejs/api-snapshot.json +207 -5
  21. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
  22. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
  25. package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
  26. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  27. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
  28. package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
  29. package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
  30. package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
  31. package/lib/vendor/blamejs/index.js +6 -0
  32. package/lib/vendor/blamejs/lib/a2a.js +4 -4
  33. package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
  34. package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
  35. package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
  36. package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
  37. package/lib/vendor/blamejs/lib/archive-read.js +8 -0
  38. package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
  39. package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
  40. package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
  41. package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
  42. package/lib/vendor/blamejs/lib/audit.js +71 -8
  43. package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
  44. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
  45. package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
  46. package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
  47. package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
  48. package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
  49. package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
  50. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
  51. package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
  52. package/lib/vendor/blamejs/lib/backup/index.js +16 -5
  53. package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
  54. package/lib/vendor/blamejs/lib/base32.js +21 -0
  55. package/lib/vendor/blamejs/lib/break-glass.js +19 -10
  56. package/lib/vendor/blamejs/lib/bundler.js +5 -1
  57. package/lib/vendor/blamejs/lib/cache-status.js +3 -7
  58. package/lib/vendor/blamejs/lib/calendar.js +21 -1
  59. package/lib/vendor/blamejs/lib/cbor.js +12 -1
  60. package/lib/vendor/blamejs/lib/cert.js +29 -11
  61. package/lib/vendor/blamejs/lib/cli.js +94 -24
  62. package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
  63. package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
  64. package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
  65. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
  66. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
  67. package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
  68. package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
  69. package/lib/vendor/blamejs/lib/content-digest.js +2 -1
  70. package/lib/vendor/blamejs/lib/cookies.js +13 -3
  71. package/lib/vendor/blamejs/lib/cose.js +31 -16
  72. package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
  73. package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
  74. package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
  75. package/lib/vendor/blamejs/lib/crypto.js +314 -19
  76. package/lib/vendor/blamejs/lib/csp.js +11 -3
  77. package/lib/vendor/blamejs/lib/daemon.js +270 -24
  78. package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
  79. package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
  80. package/lib/vendor/blamejs/lib/db-query.js +34 -7
  81. package/lib/vendor/blamejs/lib/db.js +18 -6
  82. package/lib/vendor/blamejs/lib/dbsc.js +17 -0
  83. package/lib/vendor/blamejs/lib/dev.js +21 -2
  84. package/lib/vendor/blamejs/lib/dsr.js +157 -102
  85. package/lib/vendor/blamejs/lib/external-db.js +41 -2
  86. package/lib/vendor/blamejs/lib/file-upload.js +25 -7
  87. package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
  88. package/lib/vendor/blamejs/lib/forms.js +113 -27
  89. package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
  90. package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
  91. package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
  92. package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
  93. package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
  94. package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
  95. package/lib/vendor/blamejs/lib/guard-html.js +26 -53
  96. package/lib/vendor/blamejs/lib/guard-image.js +24 -5
  97. package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
  98. package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
  99. package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
  100. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
  101. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
  102. package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
  105. package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
  106. package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
  107. package/lib/vendor/blamejs/lib/guard-time.js +1 -1
  108. package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
  109. package/lib/vendor/blamejs/lib/html-balance.js +3 -3
  110. package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
  111. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
  112. package/lib/vendor/blamejs/lib/http-client.js +39 -7
  113. package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
  114. package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
  115. package/lib/vendor/blamejs/lib/i18n.js +35 -21
  116. package/lib/vendor/blamejs/lib/incident-report.js +8 -1
  117. package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
  118. package/lib/vendor/blamejs/lib/json-path.js +23 -1
  119. package/lib/vendor/blamejs/lib/jwk.js +20 -3
  120. package/lib/vendor/blamejs/lib/link-header.js +2 -1
  121. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
  123. package/lib/vendor/blamejs/lib/log-stream.js +8 -3
  124. package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
  125. package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
  126. package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
  128. package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
  129. package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
  130. package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
  131. package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
  132. package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
  133. package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
  134. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
  136. package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
  137. package/lib/vendor/blamejs/lib/mail.js +15 -5
  138. package/lib/vendor/blamejs/lib/metrics.js +268 -63
  139. package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
  140. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
  141. package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
  142. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
  143. package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
  144. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
  145. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
  146. package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
  147. package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
  148. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
  149. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
  150. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
  151. package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
  152. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
  153. package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
  154. package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
  155. package/lib/vendor/blamejs/lib/network-dns.js +21 -2
  156. package/lib/vendor/blamejs/lib/network-tls.js +69 -7
  157. package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
  158. package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
  159. package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
  160. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
  161. package/lib/vendor/blamejs/lib/outbox.js +1 -1
  162. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
  163. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
  164. package/lib/vendor/blamejs/lib/permissions.js +6 -3
  165. package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
  166. package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
  167. package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
  168. package/lib/vendor/blamejs/lib/pubsub.js +20 -9
  169. package/lib/vendor/blamejs/lib/queue-local.js +8 -1
  170. package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
  171. package/lib/vendor/blamejs/lib/redact.js +54 -0
  172. package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
  173. package/lib/vendor/blamejs/lib/restore.js +19 -0
  174. package/lib/vendor/blamejs/lib/retention.js +12 -4
  175. package/lib/vendor/blamejs/lib/router.js +60 -6
  176. package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
  177. package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
  178. package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
  179. package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
  180. package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
  181. package/lib/vendor/blamejs/lib/safe-object.js +80 -0
  182. package/lib/vendor/blamejs/lib/safe-path.js +52 -4
  183. package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
  184. package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
  185. package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
  186. package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
  187. package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
  188. package/lib/vendor/blamejs/lib/scheduler.js +8 -1
  189. package/lib/vendor/blamejs/lib/security-assert.js +6 -6
  190. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
  191. package/lib/vendor/blamejs/lib/self-update.js +517 -87
  192. package/lib/vendor/blamejs/lib/server-timing.js +2 -4
  193. package/lib/vendor/blamejs/lib/session.js +34 -12
  194. package/lib/vendor/blamejs/lib/sql.js +15 -1
  195. package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
  196. package/lib/vendor/blamejs/lib/static.js +55 -13
  197. package/lib/vendor/blamejs/lib/storage.js +8 -2
  198. package/lib/vendor/blamejs/lib/subject.js +6 -1
  199. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
  200. package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
  201. package/lib/vendor/blamejs/lib/tsa.js +34 -13
  202. package/lib/vendor/blamejs/lib/uri-template.js +8 -1
  203. package/lib/vendor/blamejs/lib/vault/index.js +13 -0
  204. package/lib/vendor/blamejs/lib/vc.js +44 -5
  205. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
  206. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
  207. package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
  208. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
  209. package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
  210. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
  212. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
  213. package/lib/vendor/blamejs/lib/watcher.js +89 -17
  214. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
  215. package/lib/vendor/blamejs/lib/webhook.js +12 -2
  216. package/lib/vendor/blamejs/lib/ws-client.js +32 -1
  217. package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
  218. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
  219. package/lib/vendor/blamejs/package-lock.json +2 -2
  220. package/lib/vendor/blamejs/package.json +1 -1
  221. package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
  222. package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
  223. package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
  224. package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
  225. package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
  226. package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
  227. package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
  228. package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
  229. package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
  230. package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
  231. package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
  232. package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
  233. package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
  234. package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
  235. package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
  236. package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
  237. package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
  238. package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
  239. package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
  240. package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
  241. package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
  242. package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
  243. package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
  244. package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
  245. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
  246. package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
  247. package/lib/vendor/blamejs/socket.yml +94 -0
  248. package/lib/vendor/blamejs/test/00-primitives.js +605 -0
  249. package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
  250. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
  251. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
  252. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
  253. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
  254. package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
  255. package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
  256. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
  257. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
  258. package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
  259. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
  262. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
  268. package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
  284. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
  293. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
  294. package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
  302. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
  307. package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
  315. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
  317. package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
  318. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
  319. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
  320. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
  321. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
  322. package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
  323. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
  324. package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
  325. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
  326. package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
  327. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
  328. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
  329. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
  330. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
  331. package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
  334. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
  335. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
  336. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
  337. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
  341. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
  342. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
  346. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
  347. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
  348. package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
  349. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
  376. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
  388. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
  389. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
  390. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
  391. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
  392. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
  393. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
  395. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
  396. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
  397. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
  398. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
  399. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
  400. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
  401. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
  402. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
  403. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
  404. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
  405. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
  406. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
  407. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
  408. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
  409. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
  410. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
  411. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
  412. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
  413. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
  414. package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
  415. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
  416. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
  417. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
  418. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
  419. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
  420. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
  421. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
  422. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
  423. package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
  424. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
  425. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
  426. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
  427. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
  428. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
  429. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
  430. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
  431. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
  432. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
  433. package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
  434. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
  435. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
  436. package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
  437. package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
  438. package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
  439. package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
  440. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
  441. package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
  442. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
  443. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
  444. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
  445. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
  446. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
  447. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
  448. package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
  449. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
  450. package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
  451. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
  452. package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
  453. package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
  454. package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
  455. package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
  456. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
  457. package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
  458. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
  459. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
  460. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
  461. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
  462. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
  463. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
  464. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
  465. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
  466. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
  467. package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
  468. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
  469. package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
  470. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
  471. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
  472. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
  473. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
  474. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
  475. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
  476. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
  477. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
  478. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
  479. package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
  480. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
  481. package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
  482. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
  483. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
  484. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
  485. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
  486. package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
  487. package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
  488. package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
  489. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
  490. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
  491. package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
  492. package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
  493. package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
  494. package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
  495. package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
  496. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
  497. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
  498. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
  499. package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
  500. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
  501. package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
  502. package/lib/vendor/blamejs/test/smoke.js +2 -0
  503. package/package.json +1 -1
  504. package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
  505. package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
  506. package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
  507. package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
  508. package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
  509. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
  510. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
  511. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
  512. package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
  513. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
  514. package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
  515. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
  516. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
  517. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
  518. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
  519. package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
  520. package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
  521. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
@@ -0,0 +1,1230 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) blamejs contributors
3
+ "use strict";
4
+ /**
5
+ * b.metrics — error-path + adversarial-input coverage for the core
6
+ * registry (counter / gauge / histogram / exposition / requestMiddleware
7
+ * / tap dispatch) and the snapshot + shadow-registry surfaces.
8
+ *
9
+ * The happy path is exercised by the smoke + integration suites; this
10
+ * file drives the validation refusals, resource-limit rejections,
11
+ * wrong-state / unknown-command branches, and typed-error paths those
12
+ * suites never reach. Every assertion drives the public API
13
+ * (`b.metrics.*`) — never a private internal.
14
+ *
15
+ * Run standalone: `node test/layer-0-primitives/metrics.test.js`
16
+ * Or via smoke: `node test/smoke.js`
17
+ */
18
+
19
+ var helpers = require("../helpers");
20
+ var b = helpers.b;
21
+ var check = helpers.check;
22
+ var path = require("node:path");
23
+ var fs = require("node:fs");
24
+
25
+ var BACKSLASH = String.fromCharCode(92);
26
+ var NEWLINE = String.fromCharCode(10);
27
+
28
+ // Snapshot fixture — a real writable file under an isolated temp dir
29
+ // (b.testing.tempDir, the sanctioned helper). Returns the file path plus
30
+ // the dir cleanup so every test tears its scratch state down in finally.
31
+ function _snapFixture(label) {
32
+ var d = b.testing.tempDir("metrics-" + label);
33
+ return { file: path.join(d.path, "snap.json"), cleanup: d.cleanup };
34
+ }
35
+
36
+ // Shared throw-capture helpers — one shape, reused across every refusal
37
+ // assertion (audit-existing: mirrors the expectThrow shape the sibling
38
+ // metrics-snapshot / metrics-shadow-registry tests already use).
39
+ function expectCode(label, fn, codeMatch) {
40
+ var threw = null;
41
+ try { fn(); } catch (e) { threw = e; }
42
+ check(label, !!(threw && (threw.code || "").indexOf(codeMatch) !== -1));
43
+ }
44
+ function expectThrowMsg(label, fn, re) {
45
+ var threw = null;
46
+ try { fn(); } catch (e) { threw = e; }
47
+ check(label, !!(threw && re.test(threw.message || "")));
48
+ }
49
+
50
+ // ---- create() opt validation (entry-point / throw tier) ----
51
+
52
+ function testCreateRejectsUnknownOpt() {
53
+ expectThrowMsg("create: unknown opt rejected",
54
+ function () { b.metrics.create({ bogus: 1 }); },
55
+ /unknown option/);
56
+ }
57
+
58
+ function testCreateRejectsBadCardinalityCap() {
59
+ expectCode("create: cardinalityCap 0 rejected",
60
+ function () { b.metrics.create({ labelCardinalityCap: 0 }); }, "metrics/bad-opt");
61
+ expectCode("create: cardinalityCap negative rejected",
62
+ function () { b.metrics.create({ labelCardinalityCap: -1 }); }, "metrics/bad-opt");
63
+ expectCode("create: cardinalityCap non-integer rejected",
64
+ function () { b.metrics.create({ labelCardinalityCap: 1.5 }); }, "metrics/bad-opt");
65
+ expectCode("create: cardinalityCap Infinity rejected",
66
+ function () { b.metrics.create({ labelCardinalityCap: Infinity }); }, "metrics/bad-opt");
67
+ }
68
+
69
+ function testCreateRejectsBadDefaultLabelName() {
70
+ expectCode("create: invalid defaultLabels name rejected",
71
+ function () { b.metrics.create({ defaultLabels: { "bad-name": "x" } }); }, "metrics/bad-label");
72
+ }
73
+
74
+ // ---- metric-name / label-name validation ----
75
+
76
+ function testMetricNameValidation() {
77
+ var m = b.metrics.create();
78
+ expectCode("counter: hyphen in name rejected",
79
+ function () { m.counter("bad-name!", {}); }, "metrics/bad-name");
80
+ expectCode("counter: empty name rejected",
81
+ function () { m.counter("", {}); }, "metrics/bad-name");
82
+ expectCode("counter: non-string name rejected",
83
+ function () { m.counter(123, {}); }, "metrics/bad-name");
84
+ expectCode("counter: over-long name rejected",
85
+ function () { m.counter(new Array(250).join("x"), {}); }, "metrics/bad-name");
86
+ expectCode("gauge: bad labelName rejected",
87
+ function () { m.gauge("okg", { labelNames: ["bad-name"] }); }, "metrics/bad-label");
88
+ expectCode("histogram: bad labelName rejected",
89
+ function () { m.histogram("okh", { labelNames: ["also bad"] }); }, "metrics/bad-label");
90
+ }
91
+
92
+ function testDuplicateRegistration() {
93
+ var m = b.metrics.create();
94
+ m.counter("dup_total", {});
95
+ expectCode("counter: duplicate name rejected",
96
+ function () { m.counter("dup_total", {}); }, "metrics/duplicate");
97
+ // A gauge re-using a counter's fully-qualified name also collides.
98
+ expectCode("gauge: collides with existing counter name",
99
+ function () { m.gauge("dup_total", {}); }, "metrics/duplicate");
100
+ }
101
+
102
+ // ---- counter error branches ----
103
+
104
+ function testCounterDecrementRefused() {
105
+ var m = b.metrics.create();
106
+ var c = m.counter("reqs_total", {});
107
+ expectCode("counter.inc: negative value refused",
108
+ function () { c.inc(-1); }, "metrics/counter-decrement");
109
+ expectCode("counter.inc: negative with labels refused",
110
+ function () { m.counter("reqs2_total", { labelNames: ["a"] }).inc({ a: "x" }, -5); },
111
+ "metrics/counter-decrement");
112
+ }
113
+
114
+ function testLabelResolution() {
115
+ var m = b.metrics.create();
116
+ var c = m.counter("http_total", { labelNames: ["method"] });
117
+ expectCode("inc: undeclared label rejected",
118
+ function () { c.inc({ method: "GET", route: "/x" }); }, "metrics/undeclared-label");
119
+ expectCode("inc: missing required label rejected",
120
+ function () { c.inc({}); }, "metrics/missing-label");
121
+ // Declared + present → succeeds; get reflects the increment.
122
+ c.inc({ method: "GET" }, 3);
123
+ check("inc: declared label increments", c.get({ method: "GET" }) === 3);
124
+ check("get: unknown labelset defaults to 0", c.get({ method: "POST" }) === 0);
125
+ }
126
+
127
+ function testCardinalityCapDropsSilently() {
128
+ var m = b.metrics.create({ namespace: "cap", labelCardinalityCap: 2 });
129
+ var c = m.counter("k_total", { labelNames: ["id"] });
130
+ c.inc({ id: "a" });
131
+ c.inc({ id: "b" });
132
+ c.inc({ id: "c" }); // third distinct label set — over cap, dropped
133
+ check("cap: first labelset kept", c.get({ id: "a" }) === 1);
134
+ check("cap: second labelset kept", c.get({ id: "b" }) === 1);
135
+ check("cap: over-cap labelset dropped (stays 0)", c.get({ id: "c" }) === 0);
136
+ // An already-seen labelset still increments after the cap is hit.
137
+ c.inc({ id: "a" });
138
+ check("cap: existing labelset still increments post-cap", c.get({ id: "a" }) === 2);
139
+ // Exposition renders only the retained series (no third series line).
140
+ var out = m.exposition();
141
+ check("cap: over-cap series absent from exposition",
142
+ out.indexOf('cap_k_total{id="c"}') === -1);
143
+ }
144
+
145
+ // ---- gauge error branches ----
146
+
147
+ function testGaugeBadValueRefused() {
148
+ var m = b.metrics.create();
149
+ var g = m.gauge("temp", {});
150
+ expectCode("gauge.set: NaN refused",
151
+ function () { g.set(NaN); }, "metrics/gauge-bad-value");
152
+ expectCode("gauge.set: missing value (undefined) refused",
153
+ function () { g.set({}); }, "metrics/gauge-bad-value");
154
+ expectCode("gauge.set: string value refused",
155
+ function () { g.set("hot"); }, "metrics/gauge-bad-value");
156
+ // inc / dec adjust an existing series; get returns the running value.
157
+ g.set(10);
158
+ g.inc(5);
159
+ g.dec(3);
160
+ check("gauge.set/inc/dec compose", g.get() === 12);
161
+ }
162
+
163
+ // ---- histogram error branches ----
164
+
165
+ function testHistogramBadBuckets() {
166
+ var m = b.metrics.create();
167
+ expectCode("histogram: empty buckets refused",
168
+ function () { m.histogram("h1", { buckets: [] }); }, "metrics/bad-buckets");
169
+ expectCode("histogram: non-array buckets refused",
170
+ function () { m.histogram("h2", { buckets: "nope" }); }, "metrics/bad-buckets");
171
+ expectCode("histogram: non-numeric bucket boundary refused",
172
+ function () { m.histogram("h3", { buckets: [1, "x", 3] }); }, "metrics/bad-buckets");
173
+ expectCode("histogram: NaN bucket boundary refused",
174
+ function () { m.histogram("h4", { buckets: [1, NaN] }); }, "metrics/bad-buckets");
175
+ expectCode("histogram: non-ascending buckets refused (equal)",
176
+ function () { m.histogram("h5", { buckets: [1, 1] }); }, "metrics/bad-buckets");
177
+ expectCode("histogram: non-ascending buckets refused (descending)",
178
+ function () { m.histogram("h6", { buckets: [2, 1] }); }, "metrics/bad-buckets");
179
+ }
180
+
181
+ function testHistogramObserveBadValue() {
182
+ var m = b.metrics.create();
183
+ var h = m.histogram("lat", { buckets: [0.5, 1] });
184
+ expectCode("histogram.observe: NaN refused",
185
+ function () { h.observe(NaN); }, "metrics/histogram-bad-value");
186
+ expectCode("histogram.observe: string refused",
187
+ function () { h.observe("slow"); }, "metrics/histogram-bad-value");
188
+ // A valid observation lands in the right bucket + the +Inf bucket.
189
+ h.observe(0.1);
190
+ var out = m.exposition();
191
+ check("histogram: le bucket rendered", out.indexOf('lat_bucket{le="0.5"} 1') !== -1);
192
+ check("histogram: +Inf bucket rendered", out.indexOf('lat_bucket{le="+Inf"} 1') !== -1);
193
+ check("histogram: count rendered", out.indexOf("lat_count 1") !== -1);
194
+ }
195
+
196
+ // ---- exposition wire-format escaping + content negotiation ----
197
+
198
+ function testLabelValueEscaping() {
199
+ var m = b.metrics.create({ namespace: "esc" });
200
+ var c = m.counter("k_total", { labelNames: ["p"] });
201
+ c.inc({ p: 'x"y' + NEWLINE + "z" }); // short, non-credential value
202
+ var out = m.exposition();
203
+ var line = out.split(NEWLINE).filter(function (l) { return l.indexOf("esc_k_total{") === 0; })[0] || "";
204
+ check("escape: no raw newline leaks into the exposition line", line.indexOf(NEWLINE) === -1);
205
+ check("escape: double-quote escaped", line.indexOf(BACKSLASH + '"') !== -1);
206
+ check("escape: newline escaped to backslash-n", line.indexOf(BACKSLASH + "n") !== -1);
207
+ }
208
+
209
+ function testExpositionHandlerNegotiation() {
210
+ var m = b.metrics.create();
211
+ m.counter("hits_total", {}).inc();
212
+ var handler = m.expositionHandler();
213
+
214
+ function run(accept) {
215
+ var req = b.testing.mockReq({ headers: accept ? { accept: accept } : {} });
216
+ var res = b.testing.mockRes();
217
+ handler(req, res);
218
+ return res._captured();
219
+ }
220
+
221
+ var noAccept = run(null);
222
+ check("negotiate: no Accept defaults to Prometheus 0.0.4",
223
+ (noAccept.headers["content-type"] || "").indexOf("version=0.0.4") !== -1);
224
+ check("negotiate: exposition status is 200", noAccept.status === 200);
225
+ check("negotiate: Cache-Control no-store set", noAccept.headers["cache-control"] === "no-store");
226
+ check("negotiate: Content-Length is a byte count", typeof noAccept.headers["content-length"] === "number");
227
+
228
+ var om = run("application/openmetrics-text; version=1.0.0");
229
+ check("negotiate: OpenMetrics Accept selects OpenMetrics 1.0.0",
230
+ (om.headers["content-type"] || "").indexOf("openmetrics-text") !== -1);
231
+ check("negotiate: OpenMetrics body carries the # EOF terminator",
232
+ om.body.indexOf("# EOF") !== -1);
233
+
234
+ // RFC 9110 weighted negotiation: text/plain q=1 beats openmetrics q=0.
235
+ var weighted = run("text/plain;q=1.0, application/openmetrics-text;q=0");
236
+ check("negotiate: q=0 OpenMetrics loses to q=1 text/plain (Prometheus wins)",
237
+ (weighted.headers["content-type"] || "").indexOf("version=0.0.4") !== -1);
238
+ }
239
+
240
+ // ---- requestMiddleware auto-instrumentation ----
241
+
242
+ function testRequestMiddlewareCountsAndTimes() {
243
+ var m = b.metrics.create();
244
+ var mw = m.requestMiddleware();
245
+ var req = b.testing.mockReq({ method: "GET", url: "/users?q=1" });
246
+ req.routePattern = "/users/:id"; // matcher-set route template
247
+ var res = b.testing.mockRes();
248
+ var nextCalled = false;
249
+ mw(req, res, function () { nextCalled = true; });
250
+ res.writeHead(200);
251
+ res.end("body");
252
+ check("middleware: next() invoked", nextCalled === true);
253
+ var reqs = m.metrics.get("framework_http_requests_total");
254
+ check("middleware: counts by route TEMPLATE not raw path",
255
+ reqs.get({ method: "GET", route: "/users/:id", status: "200" }) === 1);
256
+ var dur = m.metrics.get("framework_http_request_duration_seconds");
257
+ check("middleware: latency histogram observed",
258
+ dur.values.size === 1);
259
+ }
260
+
261
+ // ---- tap dispatch (global no-op stub + registry-driven handler) ----
262
+
263
+ function testTapDispatch() {
264
+ b.metrics._resetForTest();
265
+ // Before any registry is active, tap is a zero-cost no-op — never throws.
266
+ var noThrow = true;
267
+ try { b.metrics.tap("audit.record", 1, { action: "x", outcome: "ok" }); }
268
+ catch (_e) { noThrow = false; }
269
+ check("tap: no-op (no throw) before a registry is active", noThrow);
270
+
271
+ var m = b.metrics.create();
272
+ b.metrics.tap("audit.record", 2, { action: "login", outcome: "success" });
273
+ check("tap: audit.record routes into framework_audit_events_total",
274
+ m.metrics.get("framework_audit_events_total").get({ action: "login", outcome: "success" }) === 2);
275
+
276
+ b.metrics.tap("queue.enqueue", 3, { queueName: "q" });
277
+ check("tap: queue.enqueue raises queue depth gauge",
278
+ m.metrics.get("framework_queue_depth").get({ queueName: "q" }) === 3);
279
+ b.metrics.tap("queue.complete", 1, { queueName: "q" });
280
+ check("tap: queue.complete lowers queue depth gauge",
281
+ m.metrics.get("framework_queue_depth").get({ queueName: "q" }) === 2);
282
+
283
+ // Unknown / unsupported tap name falls through the dispatch with no
284
+ // effect — no throw, no metric mutated.
285
+ var before = m.metrics.get("framework_errors_total").values.size;
286
+ var unknownOk = true;
287
+ try { b.metrics.tap("nonexistent.event", 1, {}); } catch (_e) { unknownOk = false; }
288
+ check("tap: unknown command is a silent no-op", unknownOk &&
289
+ m.metrics.get("framework_errors_total").values.size === before);
290
+
291
+ // deactivate() releases the global handler → tap is a no-op again.
292
+ m.deactivate();
293
+ var seal = m.metrics.get("framework_vault_seal_total").get();
294
+ b.metrics.tap("vault.seal", 1, {});
295
+ check("tap: no-op after deactivate()",
296
+ m.metrics.get("framework_vault_seal_total").get() === seal);
297
+
298
+ b.metrics._resetForTest();
299
+ }
300
+
301
+ // ---- snapshot.startWriter validation (uncovered opt branches) ----
302
+
303
+ function testSnapshotStartWriterValidation() {
304
+ function baseOpts(extra) {
305
+ var o = { path: "/tmp/metrics-cov.json", intervalMs: 1000, fields: function () { return {}; } };
306
+ var k = Object.keys(extra);
307
+ for (var i = 0; i < k.length; i++) o[k[i]] = extra[k[i]];
308
+ return o;
309
+ }
310
+ expectCode("startWriter: non-registry registry object rejected",
311
+ function () { b.metrics.snapshot.startWriter(baseOpts({ registry: 5 })); },
312
+ "metrics-snapshot/bad-registry");
313
+ expectCode("startWriter: registry without .metrics rejected",
314
+ function () { b.metrics.snapshot.startWriter(baseOpts({ registry: { nope: 1 } })); },
315
+ "metrics-snapshot/bad-registry");
316
+ expectCode("startWriter: negative fileMode rejected",
317
+ function () { b.metrics.snapshot.startWriter(baseOpts({ fileMode: -1 })); },
318
+ "metrics-snapshot/bad-file-mode");
319
+ expectCode("startWriter: fileMode above 0o777 rejected",
320
+ function () { b.metrics.snapshot.startWriter(baseOpts({ fileMode: 0o1000 })); },
321
+ "metrics-snapshot/bad-file-mode");
322
+ expectCode("startWriter: non-integer fileMode rejected",
323
+ function () { b.metrics.snapshot.startWriter(baseOpts({ fileMode: 1.5 })); },
324
+ "metrics-snapshot/bad-file-mode");
325
+ }
326
+
327
+ // ---- shadowRegistry error branches (uncovered) ----
328
+
329
+ function testShadowRegistryValidation() {
330
+ expectCode("shadow: bad onCardinalityExceeded policy rejected",
331
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", onCardinalityExceeded: "explode" }); },
332
+ "metrics-shadow/bad-policy");
333
+ expectCode("shadow: negative cardinalityCap rejected",
334
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", cardinalityCap: -1 }); },
335
+ "metrics-shadow/bad-cap");
336
+ expectCode("shadow: non-integer cardinalityCap rejected",
337
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", cardinalityCap: 1.5 }); },
338
+ "metrics-shadow/bad-cap");
339
+ expectCode("shadow: empty-string info name rejected",
340
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", info: [""] }); },
341
+ "metrics-shadow/bad-info");
342
+ expectCode("shadow: non-string counter name rejected",
343
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", counters: [123] }); },
344
+ "metrics-shadow/bad-counters");
345
+ }
346
+
347
+ function testShadowRegistryGaugeValueRefusal() {
348
+ var sh = b.metrics.snapshot.shadowRegistry({ namespace: "ns", gauges: ["gd"] });
349
+ expectCode("shadow.set: NaN gauge value refused",
350
+ function () { sh.set("gd", NaN); }, "metrics-shadow/bad-gauge-value");
351
+ expectCode("shadow.set: Infinity gauge value refused",
352
+ function () { sh.set("gd", Infinity); }, "metrics-shadow/bad-gauge-value");
353
+ expectCode("shadow.set: string gauge value refused",
354
+ function () { sh.set("gd", "x"); }, "metrics-shadow/bad-gauge-value");
355
+ }
356
+
357
+ function testShadowRegistryDropPolicyAndReset() {
358
+ // Default "drop" policy: over-cap label sets silently dropped, no throw.
359
+ var sh = b.metrics.snapshot.shadowRegistry({
360
+ namespace: "ns", counters: ["hits_total"], cardinalityCap: 2,
361
+ });
362
+ var noThrow = true;
363
+ try {
364
+ sh.inc("hits_total", { id: "a" });
365
+ sh.inc("hits_total", { id: "b" });
366
+ sh.inc("hits_total", { id: "c" }); // over cap — dropped, not thrown
367
+ } catch (_e) { noThrow = false; }
368
+ check("shadow drop-policy: over-cap inc does not throw", noThrow);
369
+ var snap = sh.snapshot();
370
+ check("shadow drop-policy: over-cap series absent",
371
+ snap.counters.hits_total['{"id":"c"}'] === undefined);
372
+ // Non-mirrored names are ignored (setInfo only stores declared names).
373
+ sh.setInfo("not_declared", "x");
374
+ check("shadow: setInfo ignores non-mirrored name",
375
+ sh.snapshot().info.not_declared === undefined);
376
+ // reset() clears all accumulated state.
377
+ sh.reset();
378
+ check("shadow reset: counters cleared",
379
+ Object.keys(sh.snapshot().counters).length === 0);
380
+ }
381
+
382
+ // ---- counter non-finite value + defaultLabels merge ----
383
+
384
+ function testCounterNonFiniteValueRefused() {
385
+ var m = b.metrics.create();
386
+ var c = m.counter("ctr_total", { labelNames: ["a"] });
387
+ expectCode("counter.inc: NaN value refused",
388
+ function () { c.inc(NaN); }, "metrics/counter-bad-value");
389
+ expectCode("counter.inc: Infinity value refused",
390
+ function () { c.inc({ a: "x" }, Infinity); }, "metrics/counter-bad-value");
391
+ }
392
+
393
+ function testDefaultLabelsMergedIntoSeries() {
394
+ // Non-empty defaultLabels drive the label-copy loop in _resolveLabels
395
+ // and attach to every rendered sample.
396
+ var m = b.metrics.create({ namespace: "dl", defaultLabels: { service: "api", version: "1" } });
397
+ var c = m.counter("hits_total", { labelNames: ["route"] });
398
+ c.inc({ route: "/x" }, 4);
399
+ check("defaultLabels: series carries the increment", c.get({ route: "/x" }) === 4);
400
+ var out = m.exposition();
401
+ check("defaultLabels: service attached to the sample line",
402
+ out.indexOf('service="api"') !== -1);
403
+ check("defaultLabels: version attached to the sample line",
404
+ out.indexOf('version="1"') !== -1);
405
+ }
406
+
407
+ // ---- gauge / histogram cardinality-cap onFull (drop-silent) ----
408
+
409
+ function testGaugeCardinalityCap() {
410
+ var m = b.metrics.create({ namespace: "gcap", labelCardinalityCap: 1 });
411
+ var g = m.gauge("depth", { labelNames: ["q"] });
412
+ g.set({ q: "a" }, 5);
413
+ g.set({ q: "b" }, 9); // second distinct set — over cap, dropped
414
+ check("gauge cap: first set kept", g.get({ q: "a" }) === 5);
415
+ check("gauge cap: over-cap set dropped (stays 0)", g.get({ q: "b" }) === 0);
416
+ // inc/dec on an over-cap (never-created) series are also no-ops.
417
+ g.inc({ q: "b" }, 3);
418
+ g.dec({ q: "b" }, 1);
419
+ check("gauge cap: inc/dec on dropped series stay 0", g.get({ q: "b" }) === 0);
420
+ }
421
+
422
+ function testHistogramCardinalityCap() {
423
+ var m = b.metrics.create({ namespace: "hcap", labelCardinalityCap: 1 });
424
+ var h = m.histogram("lat", { labelNames: ["op"], buckets: [0.5, 1] });
425
+ h.observe({ op: "a" }, 0.1);
426
+ h.observe({ op: "b" }, 0.2); // over cap — dropped
427
+ var out = m.exposition();
428
+ check("histogram cap: first series present",
429
+ out.indexOf('hcap_lat_count{op="a"} 1') !== -1);
430
+ check("histogram cap: over-cap series absent",
431
+ out.indexOf('op="b"') === -1);
432
+ }
433
+
434
+ // ---- credential-shape label redaction (adversarial input) ----
435
+
436
+ function testCredentialRedaction() {
437
+ var m = b.metrics.create({ namespace: "cred" });
438
+ var c = m.counter("k_total", { labelNames: ["tok"] });
439
+ var bearerBody = "abcdefghijklmnop";
440
+ var issuerTok = "sk-abcdefghijklmnop";
441
+ var jwtTok = "aaaaaaaa.bbbbbbbb.cccccccc";
442
+ var entropyTok = "abcdef0123456789abcdef0123456789abcdef01"; // 40 hex chars
443
+ var longBearer = "Bearer " + new Array(301).join("x"); // > CRED_MAX_SCAN, clamped
444
+ var plainLong = "hello_world_xyz"; // >= 8, not a credential
445
+ c.inc({ tok: "Bearer " + bearerBody });
446
+ c.inc({ tok: issuerTok });
447
+ c.inc({ tok: jwtTok });
448
+ c.inc({ tok: entropyTok });
449
+ c.inc({ tok: longBearer });
450
+ c.inc({ tok: plainLong });
451
+ var out = m.exposition();
452
+ check("redact: credential values replaced with the marker",
453
+ out.indexOf("[REDACTED-CREDENTIAL]") !== -1);
454
+ check("redact: raw bearer token body never reaches the scrape stream",
455
+ out.indexOf(bearerBody) === -1);
456
+ check("redact: raw issuer token absent", out.indexOf(issuerTok) === -1);
457
+ check("redact: raw JWT absent", out.indexOf(jwtTok) === -1);
458
+ check("redact: raw high-entropy token absent", out.indexOf(entropyTok) === -1);
459
+ check("redact: non-credential long value passes through verbatim",
460
+ out.indexOf(plainLong) !== -1);
461
+ }
462
+
463
+ // ---- OpenMetrics exposition (_total suffix, UNIT line, exemplars) ----
464
+
465
+ function testExpositionOpenMetricsCounterSuffixAndUnit() {
466
+ var m = b.metrics.create();
467
+ // Counter name WITHOUT the _total suffix + a declared unit: OpenMetrics
468
+ // forces the `_total` sample-line suffix and emits a `# UNIT` line.
469
+ var c = m.counter("bytes_processed", { help: "bytes", unit: "bytes" });
470
+ c.inc(7);
471
+ var out = m.exposition({ format: "openmetrics" });
472
+ check("openmetrics: counter gains _total suffix on the sample line",
473
+ out.indexOf("bytes_processed_total 7") !== -1);
474
+ check("openmetrics: TYPE line uses the suffixed name",
475
+ out.indexOf("# TYPE bytes_processed_total counter") !== -1);
476
+ check("openmetrics: UNIT line emitted for a metric with a unit",
477
+ out.indexOf("# UNIT bytes_processed_total bytes") !== -1);
478
+ check("openmetrics: EOF terminator present", out.indexOf("# EOF") !== -1);
479
+ }
480
+
481
+ function testHistogramExemplarsRendered() {
482
+ var m = b.metrics.create();
483
+ var h = m.histogram("op_seconds", { labelNames: ["op"], buckets: [0.5, 1] });
484
+ // Full exemplar (labels + explicit value + timestamp).
485
+ h.observe({ op: "a" }, 0.1, { labels: { trace_id: "T1", span_id: "S1" }, value: 0.1, timestamp: 1717000000 });
486
+ // Minimal exemplar object ({}): value falls back to the observed value,
487
+ // timestamp falls back to null — drives the false side of both ternaries.
488
+ h.observe({ op: "b" }, 0.2, {});
489
+ var out = m.exposition({ format: "openmetrics" });
490
+ check("exemplar: full exemplar renders trace_id + timestamp",
491
+ out.indexOf('# {span_id="S1",trace_id="T1"} 0.1 1717000000') !== -1);
492
+ check("exemplar: minimal exemplar renders value, empty labels, no timestamp",
493
+ out.indexOf('op_seconds_bucket{le="0.5",op="b"} 1 # 0.2\n') !== -1);
494
+ }
495
+
496
+ // Exemplar labels reach the OpenMetrics scrape stream verbatim, the same
497
+ // egress surface regular labels do — so a credential-shaped value an operator
498
+ // attaches to an exemplar (e.g. tapping a raw header alongside trace context)
499
+ // must be scrubbed the same way _resolveLabels scrubs regular labels. Redacting
500
+ // only the regular labels left the exemplar-label path raw (CWE-532). RED before
501
+ // the fix: the raw bearer / issuer / JWT / high-entropy tokens appear in the
502
+ // exposition; GREEN after: the marker replaces them and the trace context
503
+ // survives.
504
+ function testHistogramExemplarLabelsRedacted() {
505
+ var m = b.metrics.create({ namespace: "exred" });
506
+ var h = m.histogram("op_seconds", { labelNames: ["op"], buckets: [0.5, 1] });
507
+ var bearerBody = "abcdefghijklmnop"; // "Bearer <body>"
508
+ var issuerTok = "sk-abcdefghijklmnop"; // issuer-prefixed
509
+ var jwtTok = "aaaaaaaa.bbbbbbbb.cccccccc"; // JWT shape
510
+ var entropyTok = "abcdef0123456789abcdef0123456789abcdef01"; // 40 hex chars
511
+ h.observe({ op: "a" }, 0.1, {
512
+ labels: {
513
+ trace_id: "trace-keepme",
514
+ authorization: "Bearer " + bearerBody,
515
+ api_key: issuerTok,
516
+ jwt: jwtTok,
517
+ opaque: entropyTok,
518
+ },
519
+ value: 0.1,
520
+ });
521
+ var out = m.exposition({ format: "openmetrics" });
522
+ check("exemplar-redact: bearer body never reaches the scrape stream",
523
+ out.indexOf(bearerBody) === -1);
524
+ check("exemplar-redact: issuer token absent", out.indexOf(issuerTok) === -1);
525
+ check("exemplar-redact: JWT absent", out.indexOf(jwtTok) === -1);
526
+ check("exemplar-redact: high-entropy token absent", out.indexOf(entropyTok) === -1);
527
+ check("exemplar-redact: credential marker present on the exemplar line",
528
+ out.indexOf("[REDACTED-CREDENTIAL]") !== -1);
529
+ check("exemplar-redact: non-credential trace_id survives verbatim",
530
+ out.indexOf('trace_id="trace-keepme"') !== -1);
531
+ }
532
+
533
+ // Exemplar VALUE and TIMESTAMP are appended to the exposition line RAW — unlike
534
+ // labels, which _escapeLabelValue quotes — so a non-numeric operator-supplied
535
+ // value ("0.1\n# forged 999") would inject a forged metric line into every
536
+ // scrape (the same root as the exemplar-label leak, on the two numeric fields
537
+ // the label redactor doesn't cover). Both are coerced to a finite number
538
+ // (value falls back to the observation, timestamp to none) so only a bare
539
+ // number ever reaches the wire. RED before the fix: the forged line appears;
540
+ // GREEN after: it is gone and the observed value renders.
541
+ function testHistogramExemplarValueTimestampNotInjectable() {
542
+ var m = b.metrics.create({ namespace: "exinj" });
543
+ var h = m.histogram("op_seconds", { labelNames: ["op"], buckets: [0.5, 1] });
544
+ h.observe({ op: "a" }, 0.1, {
545
+ labels: { trace_id: "T1" },
546
+ value: '0.1\n# forged_bucket{le="9"} 999',
547
+ timestamp: "1717000000\n# ts_forged 1",
548
+ });
549
+ var out = m.exposition({ format: "openmetrics" });
550
+ check("exemplar-inject: a forged bucket line in exemplar.value never renders",
551
+ out.indexOf("forged_bucket") === -1);
552
+ check("exemplar-inject: a forged line in exemplar.timestamp never renders",
553
+ out.indexOf("ts_forged") === -1);
554
+ check("exemplar-inject: exemplar renders the observed numeric value (fallback), no timestamp",
555
+ out.indexOf('# {trace_id="T1"} 0.1\n') !== -1);
556
+ // A clean numeric string still coerces to a number (OpenMetrics values are
557
+ // numeric) — the guard rejects only non-finite input, it doesn't require a
558
+ // native number.
559
+ var m2 = b.metrics.create({ namespace: "exinj2" });
560
+ var h2 = m2.histogram("op_seconds", { labelNames: ["op"], buckets: [0.5, 1] });
561
+ h2.observe({ op: "a" }, 0.9, { labels: { trace_id: "T2" }, value: "0.5", timestamp: "1717000000" });
562
+ var out2 = m2.exposition({ format: "openmetrics" });
563
+ check("exemplar-inject: a clean numeric-string value coerces and renders",
564
+ out2.indexOf('# {trace_id="T2"} 0.5 1717000000') !== -1);
565
+ // A valid zero (Unix-epoch) timestamp must survive: present-vs-missing is a
566
+ // numeric check, not truthiness, so 0 renders rather than being dropped as
567
+ // falsy (the regression the coercion would otherwise introduce).
568
+ var m3 = b.metrics.create({ namespace: "exts0" });
569
+ var h3 = m3.histogram("op_seconds", { labelNames: ["op"], buckets: [0.5, 1] });
570
+ h3.observe({ op: "a" }, 0.9, { labels: { trace_id: "T3" }, value: 0.9, timestamp: "0" });
571
+ var out3 = m3.exposition({ format: "openmetrics" });
572
+ check("exemplar-inject: a valid zero (epoch) timestamp is preserved, not dropped as falsy",
573
+ out3.indexOf('# {trace_id="T3"} 0.9 0\n') !== -1);
574
+ }
575
+
576
+ // Exemplar label KEYS reach the OpenMetrics exposition through the same
577
+ // verbatim renderer (_renderLabels) as regular labels — and, unlike a label
578
+ // VALUE, a label NAME cannot be quoted or escaped in the Prometheus wire
579
+ // format. Regular label keys are gated (LABEL_NAME_RE at registration +
580
+ // _resolveLabels' undeclared-label refusal), but the exemplar path stored the
581
+ // operator-supplied key verbatim, so a key carrying a newline forged a whole
582
+ // metric line into every scrape (CWE-93 / OpenMetrics line-injection — the
583
+ // exemplar-KEY sibling of the exemplar-VALUE injection above). RED before the
584
+ // fix: a `forged_metric` line appears in the exposition; GREEN after: the
585
+ // invalid key is dropped and the valid trace_id survives.
586
+ function testHistogramExemplarLabelKeyNotInjectable() {
587
+ var m = b.metrics.create({ namespace: "exkey" });
588
+ var h = m.histogram("op_seconds", { labelNames: ["op"], buckets: [0.5, 1] });
589
+ // Hostile exemplar label name: closes the exemplar brace, injects a newline,
590
+ // and opens a forged metric family. Built from char codes so the lib source
591
+ // stays pure-ASCII-literal-free of the attack bytes. A valid trace_id rides
592
+ // alongside it in the SAME exemplar so the assertion proves selective
593
+ // key-dropping (invalid name gone, valid name kept) rather than a blanket
594
+ // exemplar drop.
595
+ var forgedKey = 'x"} 0.1' + NEWLINE + 'forged_metric{a="b';
596
+ var lbl = {};
597
+ lbl.trace_id = "keepme";
598
+ lbl[forgedKey] = "v";
599
+ h.observe({ op: "a" }, 0.1, { labels: lbl, value: 0.1 });
600
+ var out = m.exposition({ format: "openmetrics" });
601
+ check("exemplar-key: a forged metric line via a hostile exemplar label name never renders",
602
+ out.indexOf(NEWLINE + "forged_metric") === -1);
603
+ check("exemplar-key: the raw attack newline never reaches the exposition",
604
+ out.indexOf(forgedKey) === -1);
605
+ check("exemplar-key: a valid exemplar label name survives verbatim",
606
+ out.indexOf('trace_id="keepme"') !== -1);
607
+ // Every exemplar comment segment (the ` # {...} value` tail) must stay on
608
+ // one physical line — no injected key can split it across the newline the
609
+ // scraper uses as its record separator.
610
+ var lines = out.split(NEWLINE);
611
+ var okShape = true;
612
+ for (var i = 0; i < lines.length; i++) {
613
+ var hashIdx = lines[i].indexOf(" # {");
614
+ if (hashIdx === -1) continue;
615
+ // The exemplar tail must contain a closing `}` on the SAME line.
616
+ if (lines[i].indexOf("}", hashIdx) === -1) okShape = false;
617
+ }
618
+ check("exemplar-key: every exemplar comment stays on one exposition line", okShape);
619
+ }
620
+
621
+ // ---- requestMiddleware exemplar wiring + method fallback ----
622
+
623
+ function testRequestMiddlewareExemplarFromSpan() {
624
+ var m = b.metrics.create();
625
+ var mw = m.requestMiddleware();
626
+ var req = b.testing.mockReq({ method: "GET", url: "/a" });
627
+ req.span = { traceId: "trace-abc", spanId: "span-xyz", sampled: true };
628
+ var res = b.testing.mockRes();
629
+ mw(req, res, function () {});
630
+ res.writeHead(200); res.end("ok");
631
+ var dur = m.metrics.get("framework_http_request_duration_seconds");
632
+ var entry = Array.from(dur.values.values())[0];
633
+ check("middleware exemplar: server span trace_id stored on a bucket",
634
+ entry.exemplars.some(function (ex) { return ex && ex.labels && ex.labels.trace_id === "trace-abc"; }));
635
+ }
636
+
637
+ function testRequestMiddlewareExemplarFromTraceFallback() {
638
+ var m = b.metrics.create();
639
+ var mw = m.requestMiddleware();
640
+ var req = b.testing.mockReq({ method: "POST", url: "/b" });
641
+ // No req.span — the traceparent-only fallback surfaces on req.trace.
642
+ req.trace = { sampled: true, traceId: "tp-1", spanId: "tp-span-1" };
643
+ var res = b.testing.mockRes();
644
+ mw(req, res, function () {});
645
+ res.writeHead(500); res.end("err");
646
+ var dur = m.metrics.get("framework_http_request_duration_seconds");
647
+ var entry = Array.from(dur.values.values())[0];
648
+ check("middleware exemplar: req.trace fallback trace_id stored",
649
+ entry.exemplars.some(function (ex) { return ex && ex.labels && ex.labels.trace_id === "tp-1"; }));
650
+ }
651
+
652
+ function testRequestMiddlewareMethodFallback() {
653
+ var m = b.metrics.create();
654
+ var mw = m.requestMiddleware();
655
+ var req = b.testing.mockReq({ url: "/c" });
656
+ delete req.method; // absent method → counter labels default to "GET"
657
+ var res = b.testing.mockRes();
658
+ mw(req, res, function () {});
659
+ res.writeHead(200); res.end("");
660
+ var reqs = m.metrics.get("framework_http_requests_total");
661
+ check("middleware: absent method defaults to GET",
662
+ reqs.get({ method: "GET", route: "/c", status: "200" }) === 1);
663
+ }
664
+
665
+ // ---- tap dispatch: every framework hot-path branch ----
666
+
667
+ function testTapAllFrameworkBranches() {
668
+ b.metrics._resetForTest();
669
+ var m = b.metrics.create();
670
+
671
+ // audit.record with NO labels → action/outcome default to "unknown".
672
+ b.metrics.tap("audit.record", 1);
673
+ check("tap: audit.record defaults missing action/outcome to unknown",
674
+ m.metrics.get("framework_audit_events_total").get({ action: "unknown", outcome: "unknown" }) === 1);
675
+
676
+ b.metrics.tap("vault.seal", 2, {});
677
+ b.metrics.tap("vault.unseal", 3, {});
678
+ check("tap: vault.seal counted while registry active",
679
+ m.metrics.get("framework_vault_seal_total").get() === 2);
680
+ check("tap: vault.unseal counted while registry active",
681
+ m.metrics.get("framework_vault_unseal_total").get() === 3);
682
+
683
+ // queue.lease raises the inflight gauge.
684
+ b.metrics.tap("queue.lease", 2, { queueName: "q" });
685
+ check("tap: queue.lease raises inflight gauge",
686
+ m.metrics.get("framework_jobs_inflight").get({ queueName: "q" }) === 2);
687
+
688
+ // queue.fail with willRetry !== false: inflight drops, depth unchanged.
689
+ b.metrics.tap("queue.enqueue", 5, { queueName: "q" });
690
+ var depthBefore = m.metrics.get("framework_queue_depth").get({ queueName: "q" });
691
+ b.metrics.tap("queue.fail", 1, { queueName: "q", willRetry: true });
692
+ check("tap: queue.fail retry lowers inflight",
693
+ m.metrics.get("framework_jobs_inflight").get({ queueName: "q" }) === 1);
694
+ check("tap: queue.fail retry leaves depth unchanged",
695
+ m.metrics.get("framework_queue_depth").get({ queueName: "q" }) === depthBefore);
696
+ // queue.fail with willRetry === false: terminal — depth also drops.
697
+ b.metrics.tap("queue.fail", 1, { queueName: "q", willRetry: false });
698
+ check("tap: terminal queue.fail lowers depth",
699
+ m.metrics.get("framework_queue_depth").get({ queueName: "q" }) === depthBefore - 1);
700
+
701
+ // error.construct with no class → "unknown"; default queueName when omitted.
702
+ b.metrics.tap("error.construct", 1, {});
703
+ check("tap: error.construct defaults class to unknown",
704
+ m.metrics.get("framework_errors_total").get({ class: "unknown" }) === 1);
705
+ b.metrics.tap("queue.enqueue", 1); // no labels → queueName "default"
706
+ check("tap: queue.enqueue with no labels lands under 'default'",
707
+ m.metrics.get("framework_queue_depth").get({ queueName: "default" }) === 1);
708
+
709
+ b.metrics._resetForTest();
710
+ }
711
+
712
+ function testTapDefaultsFromPartialLabelsAndFalsyValue() {
713
+ b.metrics._resetForTest();
714
+ var m = b.metrics.create();
715
+ // Partial labels (object present, keyed prop absent) + falsy value (0):
716
+ // value coerces to 1, and each missing label falls to its default.
717
+ b.metrics.tap("audit.record", 0, { outcome: "ok" }); // action absent → "unknown"
718
+ check("tap: falsy value coerces to 1; missing action defaults to unknown",
719
+ m.metrics.get("framework_audit_events_total").get({ action: "unknown", outcome: "ok" }) === 1);
720
+ b.metrics.tap("queue.enqueue", 0, {}); // queueName absent → "default"; value → 1
721
+ check("tap: enqueue with empty labels defaults queueName + value",
722
+ m.metrics.get("framework_queue_depth").get({ queueName: "default" }) === 1);
723
+ b.metrics.tap("queue.lease", 0, {}); // inflight default queue, value → 1
724
+ b.metrics.tap("queue.fail", 0, {}); // willRetry absent (not false) → depth unchanged
725
+ check("tap: lease then fail(no-retry) nets inflight back to zero",
726
+ m.metrics.get("framework_jobs_inflight").get({ queueName: "default" }) === 0);
727
+ b.metrics.tap("vault.unseal", 0, {}); // value → 1
728
+ check("tap: vault.unseal falsy value coerces to 1",
729
+ m.metrics.get("framework_vault_unseal_total").get() === 1);
730
+ b.metrics.tap("error.construct", 0, {}); // class absent → "unknown"; value → 1
731
+ check("tap: error.construct with empty labels defaults class",
732
+ m.metrics.get("framework_errors_total").get({ class: "unknown" }) === 1);
733
+ b.metrics._resetForTest();
734
+ }
735
+
736
+ // ---- snapshot writer → reader round-trip (registry serialize) ----
737
+
738
+ function testSnapshotWriterReaderRegistry() {
739
+ var fx = _snapFixture("rw");
740
+ try {
741
+ var registry = b.metrics.create({ namespace: "snap" });
742
+ var c = registry.counter("reqs_total", { help: "r", labelNames: ["code"] });
743
+ c.inc({ code: "200" }, 3);
744
+ var g = registry.gauge("depth", { help: "d", labelNames: ["q"] });
745
+ g.set({ q: "main" }, 7);
746
+ var h = registry.histogram("lat_seconds", { help: "l", labelNames: ["op"], buckets: [0.01, 0.1] });
747
+ h.observe({ op: "read" }, 0.05);
748
+
749
+ var stop = b.metrics.snapshot.startWriter({
750
+ path: fx.file,
751
+ intervalMs: 100000, // large — only the sync first + stop() flushes run
752
+ registry: registry,
753
+ fields: function () { return { uptimeMs: 42 }; },
754
+ });
755
+ check("startWriter: file exists after synchronous first flush", fs.existsSync(fx.file));
756
+ stop();
757
+
758
+ var snap = b.metrics.snapshot.read(fx.file);
759
+ check("read: writtenAt is a string", typeof snap.writtenAt === "string");
760
+ check("read: flat field carried through", snap.fields.uptimeMs === 42);
761
+ check("read: registry counter serialized",
762
+ snap.metrics.snap_reqs_total.observations[0].value === 3);
763
+ check("read: registry gauge serialized",
764
+ snap.metrics.snap_depth.observations[0].value === 7);
765
+ check("read: histogram buckets + counts serialized",
766
+ Array.isArray(snap.metrics.snap_lat_seconds.buckets) &&
767
+ snap.metrics.snap_lat_seconds.observations[0].count === 1);
768
+ } finally {
769
+ fx.cleanup();
770
+ }
771
+ }
772
+
773
+ function testSnapshotWriterFlushErrorHandling() {
774
+ var fx = _snapFixture("flush");
775
+ try {
776
+ // fields() that throws: first flush swallows the error, writes nothing,
777
+ // and startWriter still returns a stop() handle.
778
+ var threwOut = false;
779
+ var stop1;
780
+ try {
781
+ stop1 = b.metrics.snapshot.startWriter({
782
+ path: fx.file,
783
+ intervalMs: 100000,
784
+ fields: function () { throw new Error("fields boom"); },
785
+ });
786
+ } catch (_e) { threwOut = true; }
787
+ check("startWriter: a throwing fields() does not escape startWriter", !threwOut);
788
+ check("startWriter: no file written when the first flush threw", !fs.existsSync(fx.file));
789
+ if (stop1) stop1();
790
+
791
+ // fields() returning a non-object is skipped (no file, no throw).
792
+ var stop2 = b.metrics.snapshot.startWriter({
793
+ path: fx.file,
794
+ intervalMs: 100000,
795
+ fields: function () { return 42; },
796
+ });
797
+ check("startWriter: non-object fields() result skips the flush", !fs.existsSync(fx.file));
798
+ stop2();
799
+ } finally {
800
+ fx.cleanup();
801
+ }
802
+ }
803
+
804
+ // ---- snapshot.read error branches ----
805
+
806
+ function testSnapshotReadErrors() {
807
+ expectCode("read: missing file rejected",
808
+ function () { b.metrics.snapshot.read(path.join(b.testing.tempDir("metrics-none").path, "absent.json")); },
809
+ "metrics-snapshot/not-found");
810
+ var fx = _snapFixture("readbad");
811
+ try {
812
+ fs.writeFileSync(fx.file, "}{ not json");
813
+ expectCode("read: malformed JSON rejected",
814
+ function () { b.metrics.snapshot.read(fx.file); }, "metrics-snapshot/bad-json");
815
+ fs.writeFileSync(fx.file, JSON.stringify({ writtenAt: "x" })); // missing fields
816
+ expectCode("read: snapshot missing fields rejected",
817
+ function () { b.metrics.snapshot.read(fx.file); }, "metrics-snapshot/bad-shape");
818
+ } finally {
819
+ fx.cleanup();
820
+ }
821
+ }
822
+
823
+ // ---- snapshot.render text (grouped, flat, ISO-date value) ----
824
+
825
+ function testSnapshotRenderTextGrouped() {
826
+ var snap = {
827
+ writtenAt: "2026-05-13T00:00:00.000Z",
828
+ fields: { count: 7, uptimeMs: 1000, at: "2026-05-13T12:00:00.000Z", extra: 3 },
829
+ };
830
+ var grouped = b.metrics.snapshot.render(snap, {
831
+ format: "text",
832
+ groups: { "Core": ["count", "uptimeMs"], "Bad": "not-an-array" },
833
+ });
834
+ check("render text: group header emitted", grouped.indexOf("== Core ==") !== -1);
835
+ check("render text: grouped field listed under its group",
836
+ grouped.indexOf("count: 7") !== -1);
837
+ check("render text: ungrouped remainder falls under Other",
838
+ grouped.indexOf("== Other ==") !== -1 && grouped.indexOf("extra: 3") !== -1);
839
+ check("render text: non-array group value skipped (no == Bad == header)",
840
+ grouped.indexOf("== Bad ==") === -1);
841
+ check("render text: ISO-date field rendered verbatim",
842
+ grouped.indexOf("at: 2026-05-13T12:00:00.000Z") !== -1);
843
+ }
844
+
845
+ // ---- snapshot.render prometheus (ISO epoch_ms + registry families) ----
846
+
847
+ function testSnapshotRenderPrometheusEpochAndFamilies() {
848
+ var snap = {
849
+ writtenAt: "2026-05-13T00:00:00.000Z",
850
+ fields: { hits_total: 5, depth: 2, at: "2026-05-13T00:00:00.000Z" },
851
+ metrics: {
852
+ served_total: {
853
+ type: "counter", help: "served things", labelNames: ["route"],
854
+ observations: [{ labels: { route: "/x" }, value: 9 }],
855
+ },
856
+ },
857
+ };
858
+ var out = b.metrics.snapshot.render(snap, { format: "prometheus", prefix: "app" });
859
+ check("render prom: _total field typed counter", out.indexOf("# TYPE app_hits_total counter") !== -1);
860
+ check("render prom: non-suffixed field typed gauge", out.indexOf("# TYPE app_depth gauge") !== -1);
861
+ check("render prom: ISO-date field emits parallel epoch_ms gauge",
862
+ out.indexOf("# TYPE app_at_epoch_ms gauge") !== -1 &&
863
+ out.indexOf("app_at_epoch_ms " + Date.parse("2026-05-13T00:00:00.000Z")) !== -1);
864
+ check("render prom: registry family rendered with its verbatim name (no prefix)",
865
+ out.indexOf('served_total{route="/x"} 9') !== -1 &&
866
+ out.indexOf("# HELP served_total served things") !== -1);
867
+ }
868
+
869
+ function testSnapshotRenderErrors() {
870
+ expectCode("render: non-object snap rejected",
871
+ function () { b.metrics.snapshot.render(null); }, "metrics-snapshot/bad-snap");
872
+ expectCode("render: unknown format rejected",
873
+ function () { b.metrics.snapshot.render({ writtenAt: "x", fields: {} }, { format: "yaml" }); },
874
+ "metrics-snapshot/bad-format");
875
+ expectCode("render: bad prometheus prefix rejected",
876
+ function () { b.metrics.snapshot.render({ writtenAt: "x", fields: {} }, { format: "prometheus", prefix: "1bad" }); },
877
+ "metrics-snapshot/bad-prefix");
878
+ expectCode("render: non-object fieldTypes rejected",
879
+ function () { b.metrics.snapshot.render({ writtenAt: "x", fields: { n: 1 } }, { format: "prometheus", fieldTypes: [] }); },
880
+ "metrics-snapshot/bad-field-types");
881
+ expectCode("render: fieldTypes value must be counter|gauge",
882
+ function () { b.metrics.snapshot.render({ writtenAt: "x", fields: { n: 1 } }, { format: "prometheus", fieldTypes: { n: "histogram" } }); },
883
+ "metrics-snapshot/bad-field-type");
884
+ }
885
+
886
+ // ---- snapshot family defensive drops (forged / hand-edited snapshot) ----
887
+
888
+ function testSnapshotFamilyDefensiveDrops() {
889
+ var snap = {
890
+ writtenAt: "2026-05-13T00:00:00.000Z",
891
+ fields: {},
892
+ metrics: {
893
+ // Whole-family drops → null, never rendered.
894
+ "not_object": "string-not-object",
895
+ "bad name\nforged 1": { type: "gauge", observations: [{ labels: {}, value: 1 }] },
896
+ "bad_type": { type: "summary", observations: [] },
897
+ "hist_no_buckets": { type: "histogram", observations: [] },
898
+ "hist_bad_bucket": { type: "histogram", buckets: ["x"], observations: [] },
899
+ // Valid families whose individual observations are dropped.
900
+ "ctr": { type: "counter", help: "c\nx", labelNames: ["ok"], observations: [
901
+ "not-an-object",
902
+ { labels: { ok: "1", "bad name\n": "z" }, value: 4 }, // forged label dropped, sample kept
903
+ { labels: {}, value: "not-a-number" }, // non-numeric value dropped
904
+ ] },
905
+ "hist_ok": { type: "histogram", buckets: [0.5, 1], observations: [
906
+ { labels: {}, counts: [1, 2], sum: 3, count: 3 }, // wrong counts length dropped
907
+ { labels: {}, counts: [1, 2, "x"], sum: 3, count: 3 }, // non-numeric count dropped
908
+ { labels: {}, counts: [1, 2, 3], sum: "nope", count: 6 }, // bad sum dropped
909
+ { labels: {}, counts: [1, 2, 3], sum: 6, count: "x" }, // bad count dropped
910
+ { counts: [1, 2, 3], sum: 6, count: 6 }, // no labels key → {} labels
911
+ ] },
912
+ // observations not an array at all → treated as empty, family renders
913
+ // metadata only (no samples).
914
+ "obs_not_array": { type: "gauge", help: "", observations: "not-an-array" },
915
+ },
916
+ };
917
+ var out = b.metrics.snapshot.render(snap, { format: "prometheus", prefix: "app" });
918
+ check("family drop: non-object family skipped", out.indexOf("not_object") === -1);
919
+ check("family drop: forged metric name skipped", out.indexOf("forged") === -1);
920
+ check("family drop: unknown type skipped", out.indexOf("bad_type") === -1);
921
+ check("family drop: bucket-less histogram skipped", out.indexOf("hist_no_buckets") === -1);
922
+ check("family drop: non-numeric bucket boundary skips family", out.indexOf("hist_bad_bucket") === -1);
923
+ check("family drop: forged label name dropped, valid sample kept",
924
+ out.indexOf('ctr{ok="1"} 4') !== -1 && out.indexOf("bad name") === -1);
925
+ check("family drop: help text newline escaped, not raw",
926
+ out.indexOf("# HELP ctr c" + BACKSLASH + "nx") !== -1);
927
+ check("family drop: only the well-formed histogram observation renders",
928
+ out.indexOf("hist_ok_count 6") !== -1 && out.indexOf("hist_ok_count 3") === -1);
929
+ check("family drop: non-array observations render metadata only",
930
+ out.indexOf("# TYPE obs_not_array gauge") !== -1);
931
+ }
932
+
933
+ // ---- shadow registry render (prometheus / openmetrics / text) ----
934
+
935
+ function testShadowRenderPrometheus() {
936
+ var sh = b.metrics.snapshot.shadowRegistry({
937
+ namespace: "tenant", counters: ["requests_total"], gauges: ["queue_depth"],
938
+ });
939
+ sh.inc("requests_total", { route: "/x" });
940
+ sh.inc("requests_total"); // no-label series
941
+ sh.set("queue_depth", 12, { queue: "main" });
942
+ var prom = sh.render({ format: "prometheus" });
943
+ check("shadow prom: labeled counter emitted with namespace prefix",
944
+ prom.indexOf('tenant_requests_total{route="/x"} 1') !== -1);
945
+ check("shadow prom: no-label counter series emitted",
946
+ prom.indexOf("tenant_requests_total 1") !== -1);
947
+ check("shadow prom: counter TYPE line is counter",
948
+ prom.indexOf("# TYPE tenant_requests_total counter") !== -1);
949
+ check("shadow prom: labeled gauge emitted",
950
+ prom.indexOf('tenant_queue_depth{queue="main"} 12') !== -1);
951
+ // openmetrics format takes the same labeled path.
952
+ var om = sh.render({ format: "openmetrics" });
953
+ check("shadow openmetrics: labeled gauge present",
954
+ om.indexOf('tenant_queue_depth{queue="main"} 12') !== -1);
955
+ }
956
+
957
+ function testShadowRenderText() {
958
+ var sh = b.metrics.snapshot.shadowRegistry({
959
+ namespace: "t", counters: ["hits_total"], gauges: ["depth"], info: ["build"],
960
+ });
961
+ sh.inc("hits_total"); // flat (no-label) counter
962
+ sh.set("depth", 3, { q: "a" }); // labeled gauge → synthetic row
963
+ sh.setInfo("build", "v1");
964
+ var text = sh.render({ format: "text" });
965
+ check("shadow text: flat counter row present", text.indexOf("hits_total: 1") !== -1);
966
+ check("shadow text: info field present", text.indexOf("build: v1") !== -1);
967
+ }
968
+
969
+ // ---- shadow registry: remaining validation + cardinality policies ----
970
+
971
+ function testShadowMoreValidation() {
972
+ expectCode("shadow: missing opts object rejected",
973
+ function () { b.metrics.snapshot.shadowRegistry(); }, "metrics-shadow/bad-opts");
974
+ expectCode("shadow: non-object opts rejected",
975
+ function () { b.metrics.snapshot.shadowRegistry("nope"); }, "metrics-shadow/bad-opts");
976
+ expectCode("shadow: namespace failing the name shape rejected",
977
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "1bad" }); },
978
+ "metrics-shadow/bad-namespace");
979
+ expectCode("shadow: non-array counters rejected",
980
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", counters: "nope" }); },
981
+ "metrics-shadow/bad-counters");
982
+ expectCode("shadow: non-array gauges rejected",
983
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", gauges: 5 }); },
984
+ "metrics-shadow/bad-gauges");
985
+ }
986
+
987
+ function testShadowCardinalityPolicies() {
988
+ // refuse: the over-cap store THROWS (and emits a rate-limited audit).
989
+ var refuse = b.metrics.snapshot.shadowRegistry({
990
+ namespace: "r", counters: ["c_total"], cardinalityCap: 1, onCardinalityExceeded: "refuse",
991
+ });
992
+ refuse.inc("c_total", { id: "a" });
993
+ expectCode("shadow refuse: over-cap inc throws",
994
+ function () { refuse.inc("c_total", { id: "b" }); }, "metrics-shadow/cardinality-exceeded");
995
+
996
+ // audit-only: over-cap is dropped without throwing.
997
+ var auditOnly = b.metrics.snapshot.shadowRegistry({
998
+ namespace: "a", gauges: ["g"], cardinalityCap: 1, onCardinalityExceeded: "audit-only",
999
+ });
1000
+ auditOnly.set("g", 1, { id: "a" });
1001
+ var noThrow = true;
1002
+ try { auditOnly.set("g", 2, { id: "b" }); } catch (_e) { noThrow = false; }
1003
+ check("shadow audit-only: over-cap gauge set does not throw", noThrow);
1004
+ check("shadow audit-only: over-cap gauge value absent",
1005
+ auditOnly.snapshot().gauges.g['{"id":"b"}'] === undefined);
1006
+
1007
+ // Re-incrementing an existing label set bumps the stored value.
1008
+ var counter = b.metrics.snapshot.shadowRegistry({ namespace: "i", counters: ["n_total"] });
1009
+ counter.inc("n_total", { id: "a" });
1010
+ counter.inc("n_total", { id: "a" });
1011
+ check("shadow: repeat inc on the same label set accumulates",
1012
+ counter.snapshot().counters.n_total['{"id":"a"}'] === 2);
1013
+ }
1014
+
1015
+ function testNullLabelValueCoercedToEmpty() {
1016
+ var m = b.metrics.create({ namespace: "nl" });
1017
+ var c = m.counter("k_total", { labelNames: ["p"] });
1018
+ c.inc({ p: null }); // null label value coerces to ""
1019
+ c.inc({ p: undefined }); // undefined coerces to "" (same series)
1020
+ check("null label: coerces to empty-string series",
1021
+ c.get({ p: null }) === 2);
1022
+ var out = m.exposition();
1023
+ check("null label: rendered as empty-string label value",
1024
+ out.indexOf('nl_k_total{p=""} 2') !== -1);
1025
+ }
1026
+
1027
+ function testSnapshotStartWriterMoreValidation() {
1028
+ var goodFields = function () { return {}; };
1029
+ expectCode("startWriter: missing path rejected",
1030
+ function () { b.metrics.snapshot.startWriter({ intervalMs: 1000, fields: goodFields }); },
1031
+ "metrics-snapshot/bad-path");
1032
+ expectCode("startWriter: interval below floor rejected",
1033
+ function () { b.metrics.snapshot.startWriter({ path: "/tmp/x.json", intervalMs: 50, fields: goodFields }); },
1034
+ "metrics-snapshot/bad-interval");
1035
+ expectCode("startWriter: non-finite interval rejected",
1036
+ function () { b.metrics.snapshot.startWriter({ path: "/tmp/x.json", intervalMs: Infinity, fields: goodFields }); },
1037
+ "metrics-snapshot/bad-interval");
1038
+ expectCode("startWriter: non-function fields rejected",
1039
+ function () { b.metrics.snapshot.startWriter({ path: "/tmp/x.json", intervalMs: 1000, fields: "nope" }); },
1040
+ "metrics-snapshot/bad-fields");
1041
+ }
1042
+
1043
+ function testSnapshotRenderTextWithFamiliesAndValueShapes() {
1044
+ var snap = {
1045
+ writtenAt: "2026-05-13T00:00:00.000Z",
1046
+ fields: {
1047
+ flag: true, // boolean → "true"
1048
+ obj: { nested: 1 }, // object → JSON.stringify branch
1049
+ plain: "just a string", // non-ISO string → verbatim
1050
+ },
1051
+ metrics: {
1052
+ served_total: { type: "counter", help: "s", labelNames: ["r"],
1053
+ observations: [{ labels: { r: "/x" }, value: 4 }] },
1054
+ depth: { type: "gauge", help: "d", labelNames: ["q"],
1055
+ observations: [{ labels: { q: "main" }, value: 8 }] },
1056
+ lat_seconds: { type: "histogram", help: "l", labelNames: ["op"], buckets: [0.5, 1],
1057
+ observations: [{ labels: { op: "read" }, counts: [1, 1, 1], sum: 0.3, count: 1 }] },
1058
+ },
1059
+ };
1060
+ var text = b.metrics.snapshot.render(snap, { format: "text" });
1061
+ check("text families: labeled counter row rendered",
1062
+ text.indexOf('served_total{r="/x"}: 4') !== -1);
1063
+ check("text families: labeled gauge row rendered",
1064
+ text.indexOf('depth{q="main"}: 8') !== -1);
1065
+ check("text families: histogram bucket + count rows rendered",
1066
+ text.indexOf('lat_seconds_bucket{le="0.5",op="read"}: 1') !== -1 &&
1067
+ text.indexOf('lat_seconds_count{op="read"}: 1') !== -1);
1068
+ check("text value: boolean field rendered as true", text.indexOf("flag: true") !== -1);
1069
+ check("text value: object field JSON-stringified",
1070
+ text.indexOf('obj: {"nested":1}') !== -1);
1071
+ check("text value: plain string rendered verbatim", text.indexOf("plain: just a string") !== -1);
1072
+ }
1073
+
1074
+ function testSnapshotRenderPrometheusFieldTypeOverrideAndSkips() {
1075
+ var longStr = new Array(70).join("a"); // > 64 chars — ISO-epoch loop skips it
1076
+ var snap = {
1077
+ writtenAt: "2026-05-13T00:00:00.000Z",
1078
+ fields: {
1079
+ ratio_total: 1, // _total but overridden to gauge
1080
+ served: 3, // no suffix, overridden to counter
1081
+ "1bad": 9, // invalid prom name — skipped
1082
+ note: "not-a-timestamp", // non-ISO string — epoch loop skips
1083
+ big: longStr, // > 64 chars — epoch loop length-skips
1084
+ "1ts": "2026-05-13T00:00:00.000Z", // ISO value but invalid prom field name
1085
+ },
1086
+ };
1087
+ var out = b.metrics.snapshot.render(snap, {
1088
+ format: "prometheus", prefix: "app",
1089
+ fieldTypes: { ratio_total: "gauge", served: "counter" },
1090
+ });
1091
+ check("fieldTypes: _total field overridden to gauge",
1092
+ out.indexOf("# TYPE app_ratio_total gauge") !== -1);
1093
+ check("fieldTypes: no-suffix field overridden to counter",
1094
+ out.indexOf("# TYPE app_served counter") !== -1);
1095
+ check("prom: invalid-name field skipped", out.indexOf("app_1bad") === -1);
1096
+ check("prom: non-ISO string field produces no epoch gauge",
1097
+ out.indexOf("app_note") === -1);
1098
+ check("prom: over-long string field produces no epoch gauge",
1099
+ out.indexOf("app_big") === -1);
1100
+ check("prom: ISO value under an invalid field name emits no epoch gauge",
1101
+ out.indexOf("1ts") === -1);
1102
+ }
1103
+
1104
+ function testShadowTextLabeledCounterAndFlatGauge() {
1105
+ var sh = b.metrics.snapshot.shadowRegistry({
1106
+ namespace: "st", counters: ["hits_total"], gauges: ["depth"],
1107
+ });
1108
+ sh.inc("hits_total", { route: "/x" }); // labeled counter → synthetic row
1109
+ sh.set("depth", 5); // flat (no-label) gauge
1110
+ var text = sh.render({ format: "text" });
1111
+ check("shadow text: labeled counter synthetic row present",
1112
+ text.indexOf("hits_total{") !== -1);
1113
+ check("shadow text: flat gauge row present", text.indexOf("depth: 5") !== -1);
1114
+ }
1115
+
1116
+ function testMetricResetClearsSeries() {
1117
+ var m = b.metrics.create({ namespace: "rst" });
1118
+ var c = m.counter("c_total", { labelNames: ["a"] });
1119
+ c.inc({ a: "x" }, 4);
1120
+ c.reset();
1121
+ check("counter.reset: series cleared", c.get({ a: "x" }) === 0);
1122
+ var g = m.gauge("g");
1123
+ g.set(5);
1124
+ g.reset();
1125
+ check("gauge.reset: value cleared", g.get() === 0);
1126
+ var h = m.histogram("h", { buckets: [1] });
1127
+ h.observe(0.5);
1128
+ h.reset();
1129
+ check("histogram.reset: observations cleared", h.values.size === 0);
1130
+ }
1131
+
1132
+ function testShadowIgnoresUndeclaredAndEmptyLabels() {
1133
+ var sh = b.metrics.snapshot.shadowRegistry({
1134
+ namespace: "u", counters: ["events"], gauges: ["g"],
1135
+ });
1136
+ // inc / set on a name not in the mirrored set are silent no-ops.
1137
+ sh.inc("undeclared_total", { a: "1" });
1138
+ sh.set("undeclared_gauge", 5, { a: "1" });
1139
+ check("shadow: inc on unmirrored counter is a no-op",
1140
+ Object.keys(sh.snapshot().counters).length === 0);
1141
+ check("shadow: set on unmirrored gauge is a no-op",
1142
+ Object.keys(sh.snapshot().gauges).length === 0);
1143
+ // Empty labels object → the no-label series (key "").
1144
+ sh.inc("events", {});
1145
+ // A mirrored counter whose name lacks the _total suffix renders as a gauge.
1146
+ var prom = sh.render({ format: "prometheus" });
1147
+ check("shadow prom: empty-labels inc lands on the no-label series",
1148
+ prom.indexOf("u_events 1") !== -1);
1149
+ check("shadow prom: non-_total counter name typed as gauge",
1150
+ prom.indexOf("# TYPE u_events gauge") !== -1);
1151
+ }
1152
+
1153
+ function testMetricFactoryDefaultsAndHeaderlessScrape() {
1154
+ var m = b.metrics.create();
1155
+ // Factories called with no options object → copts defaults to {} and the
1156
+ // histogram falls back to DEFAULT_HTTP_BUCKETS.
1157
+ m.counter("a_total").inc();
1158
+ m.gauge("g").set(3);
1159
+ var h = m.histogram("h");
1160
+ h.observe(0.02);
1161
+ check("factory defaults: histogram uses DEFAULT_HTTP_BUCKETS",
1162
+ h.buckets.length === b.metrics.DEFAULT_HTTP_BUCKETS.length);
1163
+ // Scrape handler with a request carrying no headers → defaults to
1164
+ // Prometheus 0.0.4 without dereferencing a missing headers object.
1165
+ var handler = m.expositionHandler();
1166
+ var res = b.testing.mockRes();
1167
+ handler({}, res);
1168
+ var cap = res._captured();
1169
+ check("headerless scrape: defaults to Prometheus 0.0.4",
1170
+ (cap.headers["content-type"] || "").indexOf("version=0.0.4") !== -1 && cap.status === 200);
1171
+ }
1172
+
1173
+ function run() {
1174
+ testCreateRejectsUnknownOpt();
1175
+ testCreateRejectsBadCardinalityCap();
1176
+ testCreateRejectsBadDefaultLabelName();
1177
+ testMetricNameValidation();
1178
+ testDuplicateRegistration();
1179
+ testCounterDecrementRefused();
1180
+ testLabelResolution();
1181
+ testCardinalityCapDropsSilently();
1182
+ testGaugeBadValueRefused();
1183
+ testHistogramBadBuckets();
1184
+ testHistogramObserveBadValue();
1185
+ testLabelValueEscaping();
1186
+ testExpositionHandlerNegotiation();
1187
+ testRequestMiddlewareCountsAndTimes();
1188
+ testTapDispatch();
1189
+ testSnapshotStartWriterValidation();
1190
+ testShadowRegistryValidation();
1191
+ testShadowRegistryGaugeValueRefusal();
1192
+ testShadowRegistryDropPolicyAndReset();
1193
+ testCounterNonFiniteValueRefused();
1194
+ testDefaultLabelsMergedIntoSeries();
1195
+ testGaugeCardinalityCap();
1196
+ testHistogramCardinalityCap();
1197
+ testCredentialRedaction();
1198
+ testExpositionOpenMetricsCounterSuffixAndUnit();
1199
+ testHistogramExemplarsRendered();
1200
+ testHistogramExemplarLabelsRedacted();
1201
+ testHistogramExemplarValueTimestampNotInjectable();
1202
+ testHistogramExemplarLabelKeyNotInjectable();
1203
+ testRequestMiddlewareExemplarFromSpan();
1204
+ testRequestMiddlewareExemplarFromTraceFallback();
1205
+ testRequestMiddlewareMethodFallback();
1206
+ testTapAllFrameworkBranches();
1207
+ testTapDefaultsFromPartialLabelsAndFalsyValue();
1208
+ testSnapshotWriterReaderRegistry();
1209
+ testSnapshotWriterFlushErrorHandling();
1210
+ testSnapshotReadErrors();
1211
+ testSnapshotRenderTextGrouped();
1212
+ testSnapshotRenderPrometheusEpochAndFamilies();
1213
+ testSnapshotRenderErrors();
1214
+ testSnapshotFamilyDefensiveDrops();
1215
+ testShadowRenderPrometheus();
1216
+ testShadowRenderText();
1217
+ testShadowMoreValidation();
1218
+ testShadowCardinalityPolicies();
1219
+ testNullLabelValueCoercedToEmpty();
1220
+ testSnapshotStartWriterMoreValidation();
1221
+ testSnapshotRenderTextWithFamiliesAndValueShapes();
1222
+ testSnapshotRenderPrometheusFieldTypeOverrideAndSkips();
1223
+ testShadowTextLabeledCounterAndFlatGauge();
1224
+ testMetricResetClearsSeries();
1225
+ testShadowIgnoresUndeclaredAndEmptyLabels();
1226
+ testMetricFactoryDefaultsAndHeaderlessScrape();
1227
+ }
1228
+
1229
+ if (require.main === module) run();
1230
+ module.exports = { run: run };