@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
@@ -804,6 +804,279 @@ async function run() {
804
804
  testLazyLoadRejectsInlineTranslations();
805
805
  testEagerLocalesValidation();
806
806
  testLocaleChain();
807
+
808
+ // Adversarial / defensive branch coverage + bug guards
809
+ testDirCustomRtlCaseInsensitive();
810
+ testNamespaceShadowFallsBack();
811
+ testKeyValidation();
812
+ testGetTranslationsFor();
813
+ testSetLocaleNonConfigured();
814
+ testFormatterCallSiteThrows();
815
+ testMessageFormatViaT();
816
+ testMessageFormatNamespaceSurface();
817
+ testInterpolationSameDelimiter();
818
+ testMiddlewareResolver();
819
+ testLocaleChainFallbackValidation();
820
+
821
+ // Deeper adversarial / defensive branch coverage
822
+ testValidationDeepBranches();
823
+ testResolveLocaleBadOverride();
824
+ testTnNonFiniteCount();
825
+ testPluralCategoryFallsToOther();
826
+ testNegotiateReverseMatch();
827
+ testMiddlewareEdgeCases();
828
+ testLoadDirReadFailure();
829
+ testDisplayNameCurrencyScript();
830
+ testFormatDateNumberAndString();
831
+ testInterpolationUnclosedDefault();
832
+
833
+ // Bulk feature-path coverage
834
+ testFallbackLocaleDistinctFromDefault();
835
+ testEmptyAndDottedThroughLeaf();
836
+ testPluralWithoutCount();
837
+ testTnToWithExtraVars();
838
+ testFormatNumberStyles();
839
+ testFormatDateStyles();
840
+ testFormatRelativeNumeric();
841
+ testFormatListStyles();
842
+ testDisplayNameLocaleOverride();
843
+ testLocalesGetterCopy();
844
+ testChainThroughUnpopulatedLocale();
845
+ testNegotiationEdgeBranches();
846
+ testLazyLoadDefaultEagerOnly();
847
+ testObservabilitySinkThrowSwallowed();
848
+ testMiddlewareBoundHelpers();
849
+ testMiddlewareCatchNeverCrashes();
850
+ testMiddlewareCustomHeaderName();
851
+ testMessageFormatFeaturePathsViaT();
852
+ testLocaleChainFalsyOpts();
853
+
854
+ // Residual defensive-branch coverage + untrusted-input edges
855
+ testUnvalidatedLocaleTreeStillValidated();
856
+ testBareStringLocaleTreeFallsThrough();
857
+ testPluralNonNumericCountInVars();
858
+ testTnCountArgOverridesVarsCount();
859
+ testInterpolationTrimsPlaceholderWhitespace();
860
+ testDirReflectsCurrentLocaleAfterSetLocale();
861
+ testMiddlewareResolverNonStringReturn();
862
+ testMiddlewareNonStringExplicitSourcesIgnored();
863
+ }
864
+
865
+ // create() must reject every malformed sub-opt shape at boot (the
866
+ // config-time throw tier), not just the ones the happy-path tests touch.
867
+ function testValidationDeepBranches() {
868
+ function throwsCreate(opts) {
869
+ try { b.i18n.create(opts); return false; } catch (_e) { return true; }
870
+ }
871
+ var base = { defaultLocale: "en", locales: ["en"] };
872
+ function withBase(extra) { return Object.assign({}, base, extra); }
873
+
874
+ check("interpolation as a non-object throws",
875
+ throwsCreate(withBase({ interpolation: 42 })));
876
+ check("interpolation.end empty string throws",
877
+ throwsCreate(withBase({ interpolation: { end: "" } })));
878
+ check("interpolation.escape non-function throws",
879
+ throwsCreate(withBase({ interpolation: { escape: 42 } })));
880
+ check("interpolation.strict non-boolean throws",
881
+ throwsCreate(withBase({ interpolation: { strict: "yes" } })));
882
+
883
+ check("rtlLanguages non-array throws",
884
+ throwsCreate(withBase({ rtlLanguages: "ar" })));
885
+ check("rtlLanguages with an empty-string entry throws",
886
+ throwsCreate(withBase({ rtlLanguages: ["ar", ""] })));
887
+ check("rtlLanguages with a non-string entry throws",
888
+ throwsCreate(withBase({ rtlLanguages: ["ar", 42] })));
889
+
890
+ check("translations as an array throws",
891
+ throwsCreate(withBase({ translations: [] })));
892
+ check("translations as null throws",
893
+ throwsCreate(withBase({ translations: null })));
894
+
895
+ check("fallbackLocale with an invalid BCP 47 tag throws",
896
+ throwsCreate({ defaultLocale: "en", locales: ["en", "es"], fallbackLocale: "not_a_tag" }));
897
+ check("fallbackLocale not present in locales throws",
898
+ throwsCreate({ defaultLocale: "en", locales: ["en", "es"], fallbackLocale: "fr" }));
899
+
900
+ // Translation-tree leaf that is neither a string nor a nested object.
901
+ check("translation leaf that is a number throws at load",
902
+ throwsCreate(withBase({ translations: { en: { count: 5 } } })));
903
+ check("translation leaf that is an array throws at load",
904
+ throwsCreate(withBase({ translations: { en: { list: [1, 2] } } })));
905
+
906
+ check("eagerLocales as a non-array throws",
907
+ throwsCreate({ defaultLocale: "en", locales: ["en"], lazyLoad: true, dir: "/x", eagerLocales: "en" }));
908
+ }
909
+
910
+ // A caller-supplied locale override of the wrong type or a malformed tag
911
+ // throws BAD_LOCALE at the call site (not silently coerced) — the same
912
+ // _resolveLocale guard for every t / formatter / dir entry point.
913
+ function testResolveLocaleBadOverride() {
914
+ var i = b.i18n.create({
915
+ defaultLocale: "en",
916
+ locales: ["en"],
917
+ translations: { en: { greet: "Hello" } },
918
+ });
919
+ function throwsAt(fn) { try { fn(); return false; } catch (_e) { return true; } }
920
+
921
+ check("t() with a non-string locale override throws",
922
+ throwsAt(function () { i.t("greet", null, { locale: 42 }); }));
923
+ check("t() with a malformed locale override tag throws",
924
+ throwsAt(function () { i.t("greet", null, { locale: "not_a_tag" }); }));
925
+ check("formatNumber() with a malformed locale override throws",
926
+ throwsAt(function () { i.formatNumber(5, undefined, { locale: "not_a_tag" }); }));
927
+ check("dir() with a non-string locale override throws",
928
+ throwsAt(function () { i.dir({ locale: 42 }); }));
929
+ check("has() with a malformed locale override throws",
930
+ throwsAt(function () { i.has("greet", { locale: "not_a_tag" }); }));
931
+
932
+ // A null/undefined override resolves the current locale (no throw).
933
+ check("t() with a null locale override uses the current locale",
934
+ i.t("greet", null, { locale: null }) === "Hello");
935
+ }
936
+
937
+ function testTnNonFiniteCount() {
938
+ var i = b.i18n.create({
939
+ defaultLocale: "en",
940
+ locales: ["en"],
941
+ translations: { en: { items: { one: "{count} item", other: "{count} items" } } },
942
+ });
943
+ function throwsAt(fn) { try { fn(); return false; } catch (_e) { return true; } }
944
+ check("tn() rejects NaN count", throwsAt(function () { i.tn("items", NaN); }));
945
+ check("tn() rejects Infinity count", throwsAt(function () { i.tn("items", Infinity); }));
946
+ check("tn() rejects a non-number count",
947
+ throwsAt(function () { i.tn("items", "5"); }));
948
+ }
949
+
950
+ // When Intl.PluralRules selects a CLDR category the translation entry does
951
+ // not declare, _selectPlural falls back to the mandatory `other` key rather
952
+ // than rendering undefined.
953
+ function testPluralCategoryFallsToOther() {
954
+ var i = b.i18n.create({
955
+ defaultLocale: "en",
956
+ locales: ["en", "ru"],
957
+ translations: {
958
+ en: { items: { one: "{count} item", other: "{count} items" } },
959
+ // Russian selects "few" for 2 and "many" for 5, but this entry only
960
+ // declares one + other — both must fall through to `other`.
961
+ ru: { items: { one: "{count} штука", other: "{count} (other)" } },
962
+ },
963
+ });
964
+ check("ru count=2 (selects 'few', not declared) → falls to other",
965
+ i.tn("items", 2, null, { locale: "ru" }) === "2 (other)");
966
+ check("ru count=5 (selects 'many', not declared) → falls to other",
967
+ i.tn("items", 5, null, { locale: "ru" }) === "5 (other)");
968
+ }
969
+
970
+ // Reverse negotiation: a broad requested tag ("pt") resolves to a more
971
+ // specific configured tag ("pt-BR") when no exact / prefix match exists.
972
+ function testNegotiateReverseMatch() {
973
+ var i = b.i18n.create({
974
+ defaultLocale: "en",
975
+ locales: ["en", "pt-BR"],
976
+ translations: { en: { greet: "Hello" }, "pt-BR": { greet: "Oi" } },
977
+ });
978
+ var mw = i.middleware();
979
+ var req = _mockReq();
980
+ req.headers = { "accept-language": "pt" };
981
+ mw(req, _mockRes(), function () {});
982
+ check("broad requested 'pt' reverse-matches configured 'pt-BR'",
983
+ req.locale === "pt-BR");
984
+ check("req.t bound to the reverse-matched locale",
985
+ req.t("greet") === "Oi");
986
+ }
987
+
988
+ function testMiddlewareEdgeCases() {
989
+ var i = b.i18n.create({
990
+ defaultLocale: "en",
991
+ locales: ["en", "es"],
992
+ translations: { en: { greet: "Hello" }, es: { greet: "Hola" } },
993
+ });
994
+
995
+ // res is null (next-only pipelines): must bind req.* and not crash.
996
+ var mwNoRes = i.middleware();
997
+ var reqNoRes = _mockReq();
998
+ reqNoRes.headers = { "accept-language": "es" };
999
+ var nextCalled = false;
1000
+ var crashed = false;
1001
+ try { mwNoRes(reqNoRes, null, function () { nextCalled = true; }); }
1002
+ catch (_e) { crashed = true; }
1003
+ check("middleware with res=null does not crash", crashed === false);
1004
+ check("middleware with res=null still binds req.locale + calls next",
1005
+ reqNoRes.locale === "es" && nextCalled === true);
1006
+
1007
+ // cookieName configured but the request carries no cookies → falls through
1008
+ // to header negotiation without crashing.
1009
+ var mwCookie = i.middleware({ cookieName: "lang" });
1010
+ var reqCookie = _mockReq();
1011
+ reqCookie.headers = { "accept-language": "es" };
1012
+ // no reqCookie.cookies at all
1013
+ mwCookie(reqCookie, _mockRes(), function () {});
1014
+ check("cookieName set but no cookies present → header negotiation",
1015
+ reqCookie.locale === "es");
1016
+
1017
+ // Explicit query value that is not a configured locale falls through.
1018
+ var mwQuery = i.middleware();
1019
+ var reqQuery = _mockReq();
1020
+ reqQuery.headers = { "accept-language": "es" };
1021
+ reqQuery.query = { lang: "zz-not-configured" };
1022
+ mwQuery(reqQuery, _mockRes(), function () {});
1023
+ check("query lang not in configured set → header negotiation",
1024
+ reqQuery.locale === "es");
1025
+ }
1026
+
1027
+ // _loadFromDir surfaces a read failure (not just missing/parse) as a typed
1028
+ // LOAD_FAILED — a path that exists but cannot be read as a file (a directory
1029
+ // standing where <locale>.json is expected) exercises the read-error branch.
1030
+ function testLoadDirReadFailure() {
1031
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-i18n-readfail-"));
1032
+ try {
1033
+ fs.writeFileSync(path.join(tmpDir, "en.json"), JSON.stringify({ greet: "Hello" }));
1034
+ // Create a DIRECTORY named de.json so existsSync() is true but reading
1035
+ // it as a file throws EISDIR.
1036
+ fs.mkdirSync(path.join(tmpDir, "de.json"));
1037
+ var threw = false;
1038
+ try {
1039
+ b.i18n.create({ defaultLocale: "en", locales: ["en", "de"], dir: tmpDir });
1040
+ } catch (_e) { threw = true; }
1041
+ check("unreadable locale file (directory) throws LOAD_FAILED", threw);
1042
+ } finally {
1043
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch (_e) {}
1044
+ }
1045
+ }
1046
+
1047
+ function testDisplayNameCurrencyScript() {
1048
+ var i = b.i18n.create({ defaultLocale: "en", locales: ["en"] });
1049
+ var cur = i.displayName("USD", "currency");
1050
+ check("displayName currency type returns a non-empty string",
1051
+ typeof cur === "string" && cur.length > 0);
1052
+ var scr = i.displayName("Latn", "script");
1053
+ check("displayName script type returns a non-empty string",
1054
+ typeof scr === "string" && scr.length > 0);
1055
+ }
1056
+
1057
+ // formatDate accepts a Date, a numeric epoch, or a parseable string — the
1058
+ // two non-Date branches beyond the happy-path Date input.
1059
+ function testFormatDateNumberAndString() {
1060
+ var i = b.i18n.create({ defaultLocale: "en-US", locales: ["en-US"] });
1061
+ var epoch = Date.UTC(2024, 0, 15);
1062
+ var fromNum = i.formatDate(epoch, { year: "numeric", month: "long", day: "numeric", timeZone: "UTC" });
1063
+ check("formatDate from a numeric epoch renders 2024",
1064
+ /2024/.test(fromNum) && /January/.test(fromNum));
1065
+ var fromStr = i.formatDate("2024-01-15T00:00:00Z", { year: "numeric", timeZone: "UTC" });
1066
+ check("formatDate from a parseable string renders 2024",
1067
+ /2024/.test(fromStr));
1068
+ }
1069
+
1070
+ // An unclosed default {var} delimiter is rendered literally (never crashes,
1071
+ // never drops the tail of the template).
1072
+ function testInterpolationUnclosedDefault() {
1073
+ var i = b.i18n.create({
1074
+ defaultLocale: "en",
1075
+ locales: ["en"],
1076
+ translations: { en: { partial: "Hello {name" } },
1077
+ });
1078
+ check("unclosed {var} delimiter renders literally",
1079
+ i.t("partial", { name: "Bob" }) === "Hello {name");
807
1080
  }
808
1081
 
809
1082
  function testLocaleChain() {
@@ -1003,7 +1276,886 @@ function testEagerLocalesValidation() {
1003
1276
  check("eagerLocales: must be subset of locales", threw);
1004
1277
  }
1005
1278
 
1006
- module.exports = { run: run };
1279
+ // ---- Adversarial / defensive branch coverage ----
1280
+
1281
+ // dir() folds the requested locale's primary subtag to lower case before
1282
+ // the RTL-membership test. A custom rtlLanguages list must be folded the
1283
+ // same way — otherwise an operator-supplied entry like "AR" or "CKB"
1284
+ // silently never matches and an RTL language renders left-to-right.
1285
+ function testDirCustomRtlCaseInsensitive() {
1286
+ var i = b.i18n.create({
1287
+ defaultLocale: "en",
1288
+ locales: ["en"],
1289
+ rtlLanguages: ["AR", "ckb", "KU"], // mixed / upper-case custom entries
1290
+ });
1291
+ check("dir(ar) rtl even when custom list entry is upper-case 'AR'",
1292
+ i.dir({ locale: "ar" }) === "rtl");
1293
+ check("dir(AR-EG) rtl (subtag-stripped + case-folded)",
1294
+ i.dir({ locale: "AR-EG" }) === "rtl");
1295
+ check("dir(ku) rtl even when custom list entry is upper-case 'KU'",
1296
+ i.dir({ locale: "ku" }) === "rtl");
1297
+ check("dir(ckb) rtl (lower-case custom entry)",
1298
+ i.dir({ locale: "ckb" }) === "rtl");
1299
+ check("dir(en) ltr (not in custom rtl list)",
1300
+ i.dir({ locale: "en" }) === "ltr");
1301
+ }
1302
+
1303
+ // A key that resolves to a nested namespace object in the requested locale
1304
+ // must NOT shadow a real leaf translation defined in a fallback locale —
1305
+ // the lookup should skip the non-renderable namespace and keep walking the
1306
+ // fallback chain instead of leaking the raw key into the UI.
1307
+ function testNamespaceShadowFallsBack() {
1308
+ var i = b.i18n.create({
1309
+ defaultLocale: "en",
1310
+ locales: ["en", "fr"],
1311
+ translations: {
1312
+ en: { title: "English Title", greet: "Hello" },
1313
+ fr: { title: { sub: "Sous-titre" }, greet: "Bonjour" },
1314
+ },
1315
+ });
1316
+ check("namespace in requested locale falls through to fallback leaf",
1317
+ i.t("title", null, { locale: "fr" }) === "English Title");
1318
+ check("fr's own leaf still resolves normally",
1319
+ i.t("greet", null, { locale: "fr" }) === "Bonjour");
1320
+ check("has() reports true when a fallback locale supplies the leaf",
1321
+ i.has("title", { locale: "fr" }) === true);
1322
+
1323
+ // Subtag-strip variant: pt-BR has a namespace, pt has the leaf.
1324
+ var i2 = b.i18n.create({
1325
+ defaultLocale: "en",
1326
+ locales: ["en", "pt", "pt-BR"],
1327
+ translations: {
1328
+ en: { menu: "Menu" },
1329
+ pt: { menu: "Menu PT" },
1330
+ "pt-BR": { menu: { file: "Arquivo" } }, // namespace shadows the leaf
1331
+ },
1332
+ });
1333
+ check("subtag-strip skips namespace shadow and resolves parent leaf",
1334
+ i2.t("menu", null, { locale: "pt-BR" }) === "Menu PT");
1335
+
1336
+ // A namespace key with no leaf anywhere in the chain is still a miss.
1337
+ var i3 = b.i18n.create({
1338
+ defaultLocale: "en",
1339
+ locales: ["en"],
1340
+ translations: { en: { nav: { home: "Home" } } },
1341
+ });
1342
+ check("namespace key with no leaf in chain is a miss (returns key)",
1343
+ i3.t("nav") === "nav");
1344
+ check("has() false for a pure namespace key",
1345
+ i3.has("nav") === false);
1346
+ }
1347
+
1348
+ function testKeyValidation() {
1349
+ var i = b.i18n.create({
1350
+ defaultLocale: "en",
1351
+ locales: ["en"],
1352
+ translations: { en: { greet: "Hello" } },
1353
+ });
1354
+ var threwNonString = false;
1355
+ try { i.t(123); } catch (_e) { threwNonString = true; }
1356
+ check("t() rejects non-string key", threwNonString);
1357
+
1358
+ var threwEmpty = false;
1359
+ try { i.t(""); } catch (_e) { threwEmpty = true; }
1360
+ check("t() rejects empty-string key", threwEmpty);
1361
+
1362
+ check("has() returns false for non-string key (no throw)",
1363
+ i.has(123) === false);
1364
+ check("has() returns false for empty key (no throw)",
1365
+ i.has("") === false);
1366
+ }
1367
+
1368
+ function testGetTranslationsFor() {
1369
+ var i = b.i18n.create({
1370
+ defaultLocale: "en",
1371
+ locales: ["en"],
1372
+ translations: { en: { greet: "Hello" } },
1373
+ });
1374
+ var threw = false;
1375
+ try { i.translations(123); } catch (_e) { threw = true; }
1376
+ check("translations() rejects non-string locale", threw);
1377
+ check("translations() returns null for an unloaded locale",
1378
+ i.translations("zz") === null);
1379
+ check("translations() returns the loaded tree for a known locale",
1380
+ i.translations("en") && i.translations("en").greet === "Hello");
1381
+ }
1382
+
1383
+ // setLocale permits a valid-but-unconfigured tag (operators experiment);
1384
+ // it emits i18n.miss.locale and still resolves through the fallback chain.
1385
+ function testSetLocaleNonConfigured() {
1386
+ var events = [];
1387
+ var i = b.i18n.create({
1388
+ defaultLocale: "en",
1389
+ locales: ["en"],
1390
+ observability: { event: function (name, _v, l) { events.push({ name: name, labels: l || {} }); } },
1391
+ translations: { en: { greet: "Hello" } },
1392
+ });
1393
+ i.setLocale("de"); // valid BCP 47, not in configured locales
1394
+ check("setLocale accepts a valid non-configured tag", i.locale === "de");
1395
+ check("setLocale emits i18n.miss.locale for a non-configured tag",
1396
+ events.some(function (e) { return e.name === "i18n.miss.locale" && e.labels.requested === "de"; }));
1397
+ check("t() under the non-configured locale falls through to defaultLocale",
1398
+ i.t("greet") === "Hello");
1399
+ }
1400
+
1401
+ // The formatter helpers throw a typed I18nError on the inputs they screen
1402
+ // (empty / non-array / bad enum) — the call-site-throw validation tier.
1403
+ function testFormatterCallSiteThrows() {
1404
+ var i = b.i18n.create({ defaultLocale: "en", locales: ["en"] });
1405
+
1406
+ var threwUnit = false;
1407
+ try { i.formatRelative(5, ""); } catch (_e) { threwUnit = true; }
1408
+ check("formatRelative rejects empty unit", threwUnit);
1409
+
1410
+ var threwRelVal = false;
1411
+ try { i.formatRelative(Infinity, "day"); } catch (_e) { threwRelVal = true; }
1412
+ check("formatRelative rejects non-finite value", threwRelVal);
1413
+
1414
+ var threwList = false;
1415
+ try { i.formatList("not-an-array"); } catch (_e) { threwList = true; }
1416
+ check("formatList rejects non-array", threwList);
1417
+
1418
+ var threwCode = false;
1419
+ try { i.displayName("", "language"); } catch (_e) { threwCode = true; }
1420
+ check("displayName rejects empty code", threwCode);
1421
+
1422
+ var threwDateNull = false;
1423
+ try { i.formatDate(null); } catch (_e) { threwDateNull = true; }
1424
+ check("formatDate rejects null value", threwDateNull);
1425
+ }
1426
+
1427
+ // ICU MessageFormat is auto-detected by t() when the entry carries
1428
+ // {arg, plural|select|selectordinal ...} syntax, or forced with
1429
+ // { messageFormat: true }. Drive the real t() consumer path.
1430
+ function testMessageFormatViaT() {
1431
+ var i = b.i18n.create({
1432
+ defaultLocale: "en",
1433
+ locales: ["en"],
1434
+ translations: {
1435
+ en: {
1436
+ role: "{role, select, admin {Administrator} other {Member}}",
1437
+ inbox: "You have {n, plural, =0 {no messages} one {# message} other {# messages}}.",
1438
+ rank: "{pos, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} place",
1439
+ },
1440
+ },
1441
+ });
1442
+ check("t() auto-detects select and renders the matched case",
1443
+ i.t("role", { role: "admin" }) === "Administrator");
1444
+ check("t() select falls to 'other' for an unmatched case",
1445
+ i.t("role", { role: "editor" }) === "Member");
1446
+ check("t() plural exact =0 case",
1447
+ i.t("inbox", { n: 0 }) === "You have no messages.");
1448
+ check("t() plural 'one' with # placeholder",
1449
+ i.t("inbox", { n: 1 }) === "You have 1 message.");
1450
+ check("t() plural 'other' with # placeholder",
1451
+ i.t("inbox", { n: 5 }) === "You have 5 messages.");
1452
+ check("t() selectordinal renders ordinal category",
1453
+ i.t("rank", { pos: 3 }) === "3rd place");
1454
+ check("t() selectordinal teen-boundary (21 → 21st)",
1455
+ i.t("rank", { pos: 21 }) === "21st place");
1456
+
1457
+ // Forcing messageFormat on a malformed template surfaces a typed error.
1458
+ var iBad = b.i18n.create({
1459
+ defaultLocale: "en", locales: ["en"],
1460
+ translations: { en: { broken: "{x, plural, one {a}}" } }, // missing 'other'
1461
+ });
1462
+ var threw = false;
1463
+ try { iBad.t("broken", { x: 1 }, { messageFormat: true }); } catch (_e) { threw = true; }
1464
+ check("t() with messageFormat:true throws on a malformed template", threw);
1465
+ }
1466
+
1467
+ function testMessageFormatNamespaceSurface() {
1468
+ var mf = b.i18n.messageFormat;
1469
+ check("messageFormat namespace exposes format", typeof mf.format === "function");
1470
+ check("messageFormat namespace exposes parse", typeof mf.parse === "function");
1471
+ check("messageFormat namespace exposes looksLikeMessageFormat",
1472
+ typeof mf.looksLikeMessageFormat === "function");
1473
+ check("looksLikeMessageFormat true for plural syntax",
1474
+ mf.looksLikeMessageFormat("{n, plural, other {x}}") === true);
1475
+ check("looksLikeMessageFormat false for plain interpolation",
1476
+ mf.looksLikeMessageFormat("Hello {name}") === false);
1477
+ check("mf.format select matched case",
1478
+ mf.format("{g, select, male {He} other {They}}", { g: "male" }) === "He");
1479
+ check("mf.format select unmatched → other",
1480
+ mf.format("{g, select, male {He} other {They}}", { g: "x" }) === "They");
1481
+
1482
+ // Prototype-pollution: an operator/end-user select value that names an
1483
+ // Object.prototype member must fall through to the `other` case, not return
1484
+ // an inherited member (which renders garbage, or throws when rendered as a
1485
+ // non-array — a request DoS). Every case-map lookup is own-property only.
1486
+ var protoKeys = ["__proto__", "constructor", "toString", "hasOwnProperty", "valueOf"];
1487
+ for (var pk = 0; pk < protoKeys.length; pk++) {
1488
+ var out;
1489
+ try { out = mf.format("{g, select, male {He} other {They}}", { g: protoKeys[pk] }); }
1490
+ catch (e3) { out = "THREW:" + (e3 && e3.message); }
1491
+ check("mf.format select proto-key '" + protoKeys[pk] + "' falls to other (no proto leak / DoS)",
1492
+ out === "They");
1493
+ }
1494
+ check("mf.format plural resolves its own `other` (no proto leak)",
1495
+ mf.format("{n, plural, other {N items}}", { n: 5 }) === "N items");
1496
+
1497
+ // Malformed templates fail as typed errors, never a raw crash.
1498
+ var threwUnclosed = false;
1499
+ try { mf.parse("{x, plural, other {a"); } catch (e) {
1500
+ threwUnclosed = (e && e.name === "I18nMessageFormatError");
1501
+ }
1502
+ check("mf.parse throws typed I18nMessageFormatError on unclosed body",
1503
+ threwUnclosed);
1504
+ var threwDeep = false;
1505
+ try {
1506
+ var deep = "";
1507
+ for (var d = 0; d < 300; d++) deep += "{a,select,x{";
1508
+ deep += "Z";
1509
+ for (var d2 = 0; d2 < 300; d2++) deep += "}}";
1510
+ mf.parse(deep);
1511
+ } catch (e2) { threwDeep = (e2 && e2.name === "I18nMessageFormatError"); }
1512
+ check("mf.parse caps nesting depth with a typed error (no stack overflow)",
1513
+ threwDeep);
1514
+ }
1515
+
1516
+ function testInterpolationSameDelimiter() {
1517
+ var i = b.i18n.create({
1518
+ defaultLocale: "en",
1519
+ locales: ["en"],
1520
+ interpolation: { start: "%", end: "%" },
1521
+ translations: { en: { a: "%x% and %y%", stray: "50% done" } },
1522
+ });
1523
+ check("same-delimiter interpolation replaces both placeholders",
1524
+ i.t("a", { x: "1", y: "2" }) === "1 and 2");
1525
+ check("same-delimiter: a lone unmatched delimiter is left literal",
1526
+ i.t("stray") === "50% done");
1527
+ }
1528
+
1529
+ function testMiddlewareResolver() {
1530
+ var i = b.i18n.create({
1531
+ defaultLocale: "en",
1532
+ locales: ["en", "es"],
1533
+ translations: { en: { greet: "Hello" }, es: { greet: "Hola" } },
1534
+ });
1535
+
1536
+ // Resolver wins over Accept-Language.
1537
+ var mw = i.middleware({ resolver: function (req) { return req.myLang; } });
1538
+ var req = _mockReq();
1539
+ req.headers = { "accept-language": "en" };
1540
+ req.myLang = "es";
1541
+ mw(req, _mockRes(), function () {});
1542
+ check("resolver return value wins over Accept-Language", req.locale === "es");
1543
+
1544
+ // Resolver returning an invalid / non-configured tag falls through.
1545
+ var mw2 = i.middleware({ resolver: function () { return "zz-not-configured"; } });
1546
+ var req2 = _mockReq();
1547
+ req2.headers = { "accept-language": "es" };
1548
+ mw2(req2, _mockRes(), function () {});
1549
+ check("resolver invalid value falls through to header negotiation",
1550
+ req2.locale === "es");
1551
+
1552
+ // Resolver throwing must not crash the request.
1553
+ var mw3 = i.middleware({ resolver: function () { throw new Error("resolver bug"); } });
1554
+ var req3 = _mockReq();
1555
+ req3.headers = { "accept-language": "es" };
1556
+ var nextCalled = false;
1557
+ mw3(req3, _mockRes(), function () { nextCalled = true; });
1558
+ check("resolver throw is swallowed; next() still called", nextCalled === true);
1559
+ check("resolver throw falls through to header negotiation", req3.locale === "es");
1560
+ }
1561
+
1562
+ function testLocaleChainFallbackValidation() {
1563
+ var threwBadFallback = false;
1564
+ try { b.i18n.localeChain("fr", { defaultLocale: "en", fallbackLocale: "not_a_tag" }); }
1565
+ catch (_e) { threwBadFallback = true; }
1566
+ check("localeChain rejects an invalid fallbackLocale tag", threwBadFallback);
1567
+
1568
+ var threwFallbackNotConfigured = false;
1569
+ try {
1570
+ b.i18n.localeChain("fr", { defaultLocale: "en", locales: ["en", "fr"], fallbackLocale: "de" });
1571
+ } catch (_e) { threwFallbackNotConfigured = true; }
1572
+ check("localeChain enforces fallbackLocale membership in configured locales",
1573
+ threwFallbackNotConfigured);
1574
+
1575
+ var threwBadDefault = false;
1576
+ try { b.i18n.localeChain("fr", { defaultLocale: "not_a_tag" }); }
1577
+ catch (_e) { threwBadDefault = true; }
1578
+ check("localeChain rejects an invalid defaultLocale tag", threwBadDefault);
1579
+ }
1580
+
1581
+ // ---- Bulk feature-path coverage: formatters, negotiation, fallback,
1582
+ // ICU message format, lazy load, middleware binding ----
1583
+
1584
+ // A fallbackLocale distinct from defaultLocale must appear in the resolved
1585
+ // chain AFTER the requested locale and its parents, with defaultLocale as the
1586
+ // final baseline — both cross-locale hops fire, de-duplicated.
1587
+ function testFallbackLocaleDistinctFromDefault() {
1588
+ var i = b.i18n.create({
1589
+ defaultLocale: "fr",
1590
+ fallbackLocale: "en",
1591
+ locales: ["en", "fr", "es"],
1592
+ translations: {
1593
+ en: { only_en: "EN", shared: "EN shared" },
1594
+ fr: { greet: "Bonjour" },
1595
+ },
1596
+ });
1597
+ check("chain for es is [es, en (fallback), fr (default)]",
1598
+ JSON.stringify(i._localeChain("es")) === JSON.stringify(["es", "en", "fr"]));
1599
+ check("miss in es resolves via fallbackLocale en before default fr",
1600
+ i.t("only_en", null, { locale: "es" }) === "EN");
1601
+ check("requested locale then fallback then default, de-duplicated",
1602
+ i._localeChain("en").indexOf("fr") === i._localeChain("en").length - 1);
1603
+ }
1604
+
1605
+ // An empty-string translation value renders as empty (the early-return path in
1606
+ // the interpolator), and a dotted key that walks THROUGH a string leaf returns
1607
+ // the key (never crashes descending into a non-object).
1608
+ function testEmptyAndDottedThroughLeaf() {
1609
+ var i = b.i18n.create({
1610
+ defaultLocale: "en",
1611
+ locales: ["en"],
1612
+ translations: { en: { empty: "", greet: "Hello", ns: {} } },
1613
+ });
1614
+ check("empty-string translation renders as empty string",
1615
+ i.t("empty") === "");
1616
+ check("has() true for an empty-string leaf",
1617
+ i.has("empty") === true);
1618
+ check("dotted key walking through a string leaf returns the key",
1619
+ i.t("greet.deeper.leaf") === "greet.deeper.leaf");
1620
+ check("an empty-object entry loads (not a plural shape) and is a namespace miss",
1621
+ i.t("ns") === "ns");
1622
+ }
1623
+
1624
+ // t() on a plural-shaped entry with no numeric count in vars defaults the count
1625
+ // to 0 and selects the corresponding category (en: 0 → other).
1626
+ function testPluralWithoutCount() {
1627
+ var i = b.i18n.create({
1628
+ defaultLocale: "en",
1629
+ locales: ["en"],
1630
+ translations: { en: { items: { one: "{count} item", other: "{count} items" } } },
1631
+ });
1632
+ check("plural entry with no count in vars → count 0 → other",
1633
+ i.t("items") === "{count} items");
1634
+ check("plural entry with explicit count in vars renders one",
1635
+ i.t("items", { count: 1 }) === "1 item");
1636
+ }
1637
+
1638
+ // tn / to called WITH a caller vars object merge count into a copy (rather than
1639
+ // the count-only fast path), so extra interpolation vars survive.
1640
+ function testTnToWithExtraVars() {
1641
+ var i = b.i18n.create({
1642
+ defaultLocale: "en",
1643
+ locales: ["en"],
1644
+ translations: {
1645
+ en: {
1646
+ items: { one: "{name}: {count} item", other: "{name}: {count} items" },
1647
+ place: { one: "{who} {count}st", two: "{who} {count}nd", few: "{who} {count}rd", other: "{who} {count}th" },
1648
+ },
1649
+ },
1650
+ });
1651
+ check("tn() merges caller vars alongside count",
1652
+ i.tn("items", 3, { name: "Cart" }) === "Cart: 3 items");
1653
+ check("tn() singular with caller vars",
1654
+ i.tn("items", 1, { name: "Cart" }) === "Cart: 1 item");
1655
+ check("to() merges caller vars alongside ordinal count",
1656
+ i.to("place", 2, { who: "Runner" }) === "Runner 2nd");
1657
+ }
1658
+
1659
+ // formatNumber across styles/locales — percent, currency, unit, notation — the
1660
+ // bulk Intl.NumberFormat surface an operator drives.
1661
+ function testFormatNumberStyles() {
1662
+ var i = b.i18n.create({
1663
+ defaultLocale: "en-US",
1664
+ locales: ["en-US", "de-DE", "ja-JP"],
1665
+ });
1666
+ check("formatNumber percent",
1667
+ i.formatNumber(0.25, { style: "percent" }) === "25%");
1668
+ check("formatNumber currency EUR under de-DE",
1669
+ i.formatNumber(1234.5, { style: "currency", currency: "EUR" }, { locale: "de-DE" }).indexOf("€") !== -1);
1670
+ check("formatNumber currency JPY has no fraction digits",
1671
+ i.formatNumber(1234, { style: "currency", currency: "JPY" }, { locale: "ja-JP" }).indexOf("1,234") !== -1);
1672
+ check("formatNumber unit (kilometer)",
1673
+ typeof i.formatNumber(5, { style: "unit", unit: "kilometer" }) === "string" &&
1674
+ i.formatNumber(5, { style: "unit", unit: "kilometer" }).indexOf("5") !== -1);
1675
+ check("formatNumber compact notation",
1676
+ i.formatNumber(1200000, { notation: "compact" }).length > 0);
1677
+ check("formatNumber minimumFractionDigits pads",
1678
+ i.formatNumber(5, { minimumFractionDigits: 2 }) === "5.00");
1679
+ check("formatNumber -0 is finite and formats",
1680
+ i.formatNumber(-0) === "-0" || i.formatNumber(-0) === "0");
1681
+ }
1682
+
1683
+ // formatDate across dateStyle/timeStyle presets and the no-formatOpts branch
1684
+ // (falls to the locale default formatter).
1685
+ function testFormatDateStyles() {
1686
+ var i = b.i18n.create({ defaultLocale: "en-US", locales: ["en-US", "ja-JP"] });
1687
+ var d = new Date(Date.UTC(2024, 0, 15, 13, 30, 0));
1688
+ check("formatDate with no formatOpts returns a non-empty string",
1689
+ typeof i.formatDate(d) === "string" && i.formatDate(d).length > 0);
1690
+ check("formatDate dateStyle:full contains 2024",
1691
+ /2024/.test(i.formatDate(d, { dateStyle: "full", timeZone: "UTC" })));
1692
+ check("formatDate timeStyle:short renders a time",
1693
+ /\d/.test(i.formatDate(d, { timeStyle: "short", timeZone: "UTC" })));
1694
+ check("formatDate ja-JP dateStyle:long contains 年",
1695
+ /年/.test(i.formatDate(d, { dateStyle: "long", timeZone: "UTC" }, { locale: "ja-JP" })));
1696
+ }
1697
+
1698
+ // formatRelative with the `numeric` opt threads it into the formatter — "auto"
1699
+ // yields word forms ("today" / "tomorrow"), "always" keeps the numeric form.
1700
+ function testFormatRelativeNumeric() {
1701
+ var i = b.i18n.create({ defaultLocale: "en", locales: ["en"] });
1702
+ check("formatRelative numeric:auto 0 day → 'today'",
1703
+ i.formatRelative(0, "day", { numeric: "auto" }) === "today");
1704
+ check("formatRelative numeric:auto -1 day → 'yesterday'",
1705
+ i.formatRelative(-1, "day", { numeric: "auto" }) === "yesterday");
1706
+ check("formatRelative numeric:always 0 day keeps numeric form",
1707
+ i.formatRelative(0, "day", { numeric: "always" }) === "in 0 days");
1708
+ check("formatRelative default (no numeric) uses numeric form",
1709
+ i.formatRelative(0, "day") === "in 0 days");
1710
+ }
1711
+
1712
+ // formatList across type + style — conjunction/disjunction/unit and short/narrow.
1713
+ function testFormatListStyles() {
1714
+ var i = b.i18n.create({ defaultLocale: "en", locales: ["en"] });
1715
+ check("formatList unit type joins without 'and'",
1716
+ i.formatList(["5 min", "30 sec"], { type: "unit" }).indexOf("5 min") !== -1);
1717
+ check("formatList disjunction short style",
1718
+ typeof i.formatList(["A", "B"], { type: "disjunction", style: "short" }) === "string");
1719
+ check("formatList single item returns that item",
1720
+ i.formatList(["Only"]) === "Only");
1721
+ check("formatList two items conjunction",
1722
+ i.formatList(["A", "B"]) === "A and B");
1723
+ }
1724
+
1725
+ // displayName currency/script honor a caller locale override.
1726
+ function testDisplayNameLocaleOverride() {
1727
+ var i = b.i18n.create({ defaultLocale: "en", locales: ["en", "fr"] });
1728
+ check("displayName region under fr locale is localized",
1729
+ typeof i.displayName("US", "region", { locale: "fr" }) === "string");
1730
+ check("displayName currency under a locale override renders",
1731
+ i.displayName("EUR", "currency", { locale: "fr" }).length > 0);
1732
+ check("displayName script under a locale override renders",
1733
+ i.displayName("Latn", "script", { locale: "fr" }).length > 0);
1734
+ }
1735
+
1736
+ // i.locales() returns a defensive copy of the configured set.
1737
+ function testLocalesGetterCopy() {
1738
+ var i = b.i18n.create({ defaultLocale: "en", locales: ["en", "es", "fr"] });
1739
+ var l1 = i.locales();
1740
+ check("locales() returns the configured set",
1741
+ JSON.stringify(l1) === JSON.stringify(["en", "es", "fr"]));
1742
+ l1.push("zz");
1743
+ check("locales() returns a copy — mutating it does not affect the instance",
1744
+ i.locales().indexOf("zz") === -1);
1745
+ }
1746
+
1747
+ // A non-lazy instance whose fallback chain includes a configured locale with no
1748
+ // inline translations tree still resolves (the load-ensure no-ops, chain walks on).
1749
+ function testChainThroughUnpopulatedLocale() {
1750
+ var i = b.i18n.create({
1751
+ defaultLocale: "en",
1752
+ locales: ["en", "es", "fr"],
1753
+ translations: { en: { greet: "Hello" } }, // es + fr have no tree
1754
+ });
1755
+ check("lookup under es (no tree) falls through to en",
1756
+ i.t("greet", null, { locale: "es" }) === "Hello");
1757
+ check("lookup under fr (no tree) falls through to en",
1758
+ i.t("greet", null, { locale: "fr" }) === "Hello");
1759
+ check("translations() returns null for a configured-but-unpopulated locale",
1760
+ i.translations("es") === null);
1761
+ }
1762
+
1763
+ // Accept-Language negotiation edge branches: an all-q=0 list excludes every
1764
+ // entry and falls to the default; a multi-level requested tag prefix-matches a
1765
+ // broader configured tag by stripping subtags one at a time.
1766
+ function testNegotiationEdgeBranches() {
1767
+ var i = b.i18n.create({
1768
+ defaultLocale: "en",
1769
+ locales: ["en", "zh", "pt"],
1770
+ translations: { en: { g: "Hello" }, zh: { g: "你好" }, pt: { g: "Olá" } },
1771
+ });
1772
+ function loc(header) {
1773
+ var req = _mockReq();
1774
+ req.headers = { "accept-language": header };
1775
+ i.middleware()(req, _mockRes(), function () {});
1776
+ return req.locale;
1777
+ }
1778
+ check("all-q=0 Accept-Language excludes everything → defaultLocale",
1779
+ loc("zh;q=0,pt;q=0") === "en");
1780
+ check("multi-level tag zh-Hant-TW prefix-matches configured zh",
1781
+ loc("zh-Hant-TW") === "zh");
1782
+ check("single q=0 entry → defaultLocale",
1783
+ loc("pt;q=0") === "en");
1784
+ }
1785
+
1786
+ // lazyLoad with no eagerLocales loads only the defaultLocale at create; other
1787
+ // locales stream in on first lookup.
1788
+ function testLazyLoadDefaultEagerOnly() {
1789
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-i18n-lazydef-"));
1790
+ try {
1791
+ fs.writeFileSync(path.join(tmpDir, "en.json"), JSON.stringify({ greet: "Hello" }));
1792
+ fs.writeFileSync(path.join(tmpDir, "es.json"), JSON.stringify({ greet: "Hola" }));
1793
+ var i = b.i18n.create({
1794
+ defaultLocale: "en",
1795
+ locales: ["en", "es"],
1796
+ lazyLoad: true, // no eagerLocales → defaults to [defaultLocale]
1797
+ dir: tmpDir,
1798
+ });
1799
+ check("lazyLoad w/o eagerLocales: default locale available immediately",
1800
+ i.t("greet") === "Hello");
1801
+ check("lazyLoad w/o eagerLocales: other locale streams in on demand",
1802
+ i.t("greet", null, { locale: "es" }) === "Hola");
1803
+ // A valid-but-unconfigured locale override on a lazy instance: the
1804
+ // load-ensure sees it is not in the configured set and no-ops, so the
1805
+ // lookup falls through the chain to the default locale (no file read,
1806
+ // no crash).
1807
+ check("lazy instance: unconfigured locale override falls through to default",
1808
+ i.t("greet", null, { locale: "de" }) === "Hello");
1809
+ } finally {
1810
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch (_e) {}
1811
+ }
1812
+ }
1813
+
1814
+ // An observability sink that throws must never break a translation call — the
1815
+ // emit is wrapped drop-silent.
1816
+ function testObservabilitySinkThrowSwallowed() {
1817
+ var i = b.i18n.create({
1818
+ defaultLocale: "en",
1819
+ locales: ["en"],
1820
+ observability: { event: function () { throw new Error("sink boom"); } },
1821
+ translations: { en: { greet: "Hello" } },
1822
+ });
1823
+ var v;
1824
+ var crashed = false;
1825
+ try { v = i.t("does.not.exist"); } catch (_e) { crashed = true; }
1826
+ check("throwing observability sink does not crash t()", crashed === false);
1827
+ check("t() still returns the key when the sink throws", v === "does.not.exist");
1828
+ }
1829
+
1830
+ // The middleware binds req.t / req.tn / req.to / req.dir and mirrors them onto
1831
+ // res.locals; the bound helpers default the locale to the negotiated one while
1832
+ // still honoring an explicit override.
1833
+ function testMiddlewareBoundHelpers() {
1834
+ var i = b.i18n.create({
1835
+ defaultLocale: "en",
1836
+ locales: ["en", "es"],
1837
+ translations: {
1838
+ en: { greet: "Hello", items: { one: "{count} item", other: "{count} items" },
1839
+ rank: { one: "{count}st", two: "{count}nd", few: "{count}rd", other: "{count}th" } },
1840
+ es: { greet: "Hola", items: { one: "{count} artículo", other: "{count} artículos" },
1841
+ rank: { one: "{count}º", two: "{count}º", few: "{count}º", other: "{count}º" } },
1842
+ },
1843
+ });
1844
+ var req = _mockReq();
1845
+ req.headers = { "accept-language": "es" };
1846
+ var res = _mockRes();
1847
+ i.middleware()(req, res, function () {});
1848
+
1849
+ check("req.tn bound to the negotiated locale",
1850
+ req.tn("items", 5) === "5 artículos");
1851
+ check("req.to bound to the negotiated locale",
1852
+ req.to("rank", 1) === "1º");
1853
+ check("req.to honors an explicit locale override in callerOpts",
1854
+ req.to("rank", 1, null, { locale: "en" }) === "1st");
1855
+ check("req.t honors an explicit locale override over the negotiated one",
1856
+ req.t("greet", null, { locale: "en" }) === "Hello");
1857
+ check("req.tn honors an explicit locale override",
1858
+ req.tn("items", 1, null, { locale: "en" }) === "1 item");
1859
+ check("req.dir returns a direction for the negotiated locale",
1860
+ req.dir() === "ltr");
1861
+ check("res.locals.to bound", typeof res.locals.to === "function");
1862
+ check("res.locals.tn bound", typeof res.locals.tn === "function");
1863
+ check("res.locals.t via res.locals resolves the negotiated locale",
1864
+ res.locals.t("greet") === "Hola");
1865
+ }
1866
+
1867
+ // The middleware never lets an i18n error escape onto the request path: if
1868
+ // reading a request field throws, it swallows, sets req.locale to the current
1869
+ // default, and still calls next().
1870
+ function testMiddlewareCatchNeverCrashes() {
1871
+ var i = b.i18n.create({
1872
+ defaultLocale: "en",
1873
+ locales: ["en"],
1874
+ translations: { en: { greet: "Hello" } },
1875
+ });
1876
+ var req = _mockReq();
1877
+ req.headers = {};
1878
+ // A query getter that throws forces the try/catch guard in the middleware.
1879
+ Object.defineProperty(req, "query", {
1880
+ get: function () { throw new Error("query access boom"); },
1881
+ configurable: true,
1882
+ });
1883
+ var res = _mockRes();
1884
+ var nextCalled = false;
1885
+ var crashed = false;
1886
+ try { i.middleware()(req, res, function () { nextCalled = true; }); }
1887
+ catch (_e) { crashed = true; }
1888
+ check("middleware swallows a throwing request field", crashed === false);
1889
+ check("middleware still calls next() after swallowing", nextCalled === true);
1890
+ check("middleware falls back to the current default locale on error",
1891
+ req.locale === "en");
1892
+ }
1893
+
1894
+ // A custom headerName reads the negotiation source from a non-standard header.
1895
+ function testMiddlewareCustomHeaderName() {
1896
+ var i = b.i18n.create({
1897
+ defaultLocale: "en",
1898
+ locales: ["en", "es"],
1899
+ translations: { en: { greet: "Hello" }, es: { greet: "Hola" } },
1900
+ });
1901
+ var req = _mockReq();
1902
+ req.headers = { "x-locale": "es" };
1903
+ i.middleware({ headerName: "X-Locale" })(req, _mockRes(), function () {});
1904
+ check("custom headerName negotiates from the named header",
1905
+ req.locale === "es");
1906
+ }
1907
+
1908
+ // ICU MessageFormat feature surface driven through t(): nested plural inside
1909
+ // select, plural offset, selectordinal, and the # placeholder.
1910
+ function testMessageFormatFeaturePathsViaT() {
1911
+ var i = b.i18n.create({
1912
+ defaultLocale: "en",
1913
+ locales: ["en"],
1914
+ translations: {
1915
+ en: {
1916
+ nested: "{tier, select, pro {{n, plural, one {# pro seat} other {# pro seats}}} other {{n, plural, one {# seat} other {# seats}}}}",
1917
+ party: "{n, plural, offset:1 =0 {nobody} one {you and # other} other {you and # others}}",
1918
+ medal: "{p, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} place",
1919
+ exact: "{n, plural, =0 {no items} =1 {a single item} other {# items}}",
1920
+ },
1921
+ },
1922
+ });
1923
+ check("nested select→plural (pro, one)",
1924
+ i.t("nested", { tier: "pro", n: 1 }) === "1 pro seat");
1925
+ check("nested select→plural (pro, other)",
1926
+ i.t("nested", { tier: "pro", n: 4 }) === "4 pro seats");
1927
+ check("nested select falls to other branch",
1928
+ i.t("nested", { tier: "free", n: 2 }) === "2 seats");
1929
+ check("plural offset =0 exact case",
1930
+ i.t("party", { n: 0 }) === "nobody");
1931
+ check("plural offset one case subtracts the offset in #",
1932
+ i.t("party", { n: 2 }) === "you and 1 other");
1933
+ check("plural offset other case subtracts the offset in #",
1934
+ i.t("party", { n: 4 }) === "you and 3 others");
1935
+ check("selectordinal few (3rd)",
1936
+ i.t("medal", { p: 3 }) === "3rd place");
1937
+ check("selectordinal other (11th)",
1938
+ i.t("medal", { p: 11 }) === "11th place");
1939
+ check("plural exact =1 literal case beats the 'one' category",
1940
+ i.t("exact", { n: 1 }) === "a single item");
1941
+ check("plural exact falls to other for a non-literal count",
1942
+ i.t("exact", { n: 7 }) === "7 items");
1943
+
1944
+ // messageFormat: true forces the ICU path even for a plain-looking entry.
1945
+ var i2 = b.i18n.create({
1946
+ defaultLocale: "en", locales: ["en"],
1947
+ translations: { en: { plain: "just text {x}" } },
1948
+ });
1949
+ check("messageFormat:true on a plain entry renders the literal placeholder text",
1950
+ typeof i2.t("plain", { x: "v" }, { messageFormat: true }) === "string");
1951
+ }
1952
+
1953
+ // localeChain called with a falsy opts argument still validates (and throws on
1954
+ // the now-missing defaultLocale) rather than dereferencing undefined.
1955
+ function testLocaleChainFalsyOpts() {
1956
+ var threw = false;
1957
+ try { b.i18n.localeChain("fr", null); } catch (_e) { threw = true; }
1958
+ check("localeChain('fr', null) throws (defaultLocale required)", threw);
1959
+
1960
+ // A configured-set that DOES include the members passes membership validation
1961
+ // and returns the chain (the happy path through the membership guard).
1962
+ var chain = b.i18n.localeChain("fr-CA", {
1963
+ defaultLocale: "en", fallbackLocale: "en", locales: ["en", "fr", "fr-CA"],
1964
+ });
1965
+ check("localeChain with a valid configured set returns the chain",
1966
+ JSON.stringify(chain) === JSON.stringify(["fr-CA", "fr", "en"]));
1967
+ }
1968
+
1969
+ // Every inline translation tree is validated at create — including a locale
1970
+ // present in `translations` but absent from the configured `locales` array. Such
1971
+ // a locale is still reachable via an explicit locale override, so the shape /
1972
+ // plural invariants the lookup relies on (notably _selectPlural assuming a
1973
+ // mandatory `other`) must hold for it too. A malformed tree there is rejected at
1974
+ // boot (fail-closed) rather than silently accepted and left to make t() return
1975
+ // undefined at request time — the contract is that t() returns a string.
1976
+ function testUnvalidatedLocaleTreeStillValidated() {
1977
+ // A non-string / non-object leaf in a non-configured locale is rejected.
1978
+ var threwLeaf = null;
1979
+ try {
1980
+ b.i18n.create({
1981
+ defaultLocale: "en", locales: ["en"],
1982
+ translations: { en: { greet: "Hello" }, zz: { num: 123 } },
1983
+ });
1984
+ } catch (e) { threwLeaf = e; }
1985
+ check("non-configured locale tree is validated: a non-string leaf is rejected at create",
1986
+ threwLeaf !== null && /string or nested object/.test(threwLeaf.message));
1987
+ // A plural entry missing the mandatory `other` in a non-configured locale is
1988
+ // rejected too — otherwise t(count=5) selecting the CLDR `other` category
1989
+ // would return undefined instead of the key.
1990
+ var threwPlural = null;
1991
+ try {
1992
+ b.i18n.create({
1993
+ defaultLocale: "en", locales: ["en"],
1994
+ translations: { en: {}, zz: { items: { one: "uno" } } },
1995
+ });
1996
+ } catch (e) { threwPlural = e; }
1997
+ check("non-configured locale plural entry missing `other` is rejected at create",
1998
+ threwPlural !== null);
1999
+ // A well-formed non-configured locale is accepted and usable via override.
2000
+ var i = b.i18n.create({
2001
+ defaultLocale: "en", locales: ["en"],
2002
+ translations: { en: { greet: "Hello" }, zz: { greet: "Hallo" } },
2003
+ });
2004
+ check("a well-formed non-configured locale is usable via an explicit override",
2005
+ i.t("greet", null, { locale: "zz" }) === "Hallo");
2006
+ }
2007
+
2008
+ // _validateTranslationTree treats a bare string as a valid leaf at ANY depth,
2009
+ // including the tree root, so `translations: { de: "just-a-string" }` is accepted
2010
+ // at create. A subsequent lookup resolving to that locale hands _resolveKey a
2011
+ // non-object `tree`; its guard returns undefined and the chain walk falls through
2012
+ // to a locale that carries a real object tree — no crash, no raw-key leak.
2013
+ function testBareStringLocaleTreeFallsThrough() {
2014
+ var i = b.i18n.create({
2015
+ defaultLocale: "en",
2016
+ locales: ["en", "de"],
2017
+ translations: { en: { greet: "Hello" }, de: "not-an-object-tree" },
2018
+ });
2019
+ check("bare-string locale tree: lookup falls through to a real tree",
2020
+ i.t("greet", null, { locale: "de" }) === "Hello");
2021
+ check("has() resolves the leaf from the fallback despite a bare-string tree",
2022
+ i.has("greet", { locale: "de" }) === true);
2023
+ check("translations() returns the bare-string tree verbatim",
2024
+ i.translations("de") === "not-an-object-tree");
2025
+ }
2026
+
2027
+ // A plural-shaped entry's CLDR category is selected from the numeric `count`.
2028
+ // When `count` is present in vars but NOT a number (a stringified digit), it does
2029
+ // not drive selection — the code defaults the selection count to 0 (→ the "other"
2030
+ // category for en) while the raw string value still interpolates into `{count}`.
2031
+ // So a string "1" renders the plural (not singular) form.
2032
+ function testPluralNonNumericCountInVars() {
2033
+ var i = b.i18n.create({
2034
+ defaultLocale: "en",
2035
+ locales: ["en"],
2036
+ translations: { en: { items: { one: "{count} item", other: "{count} items" } } },
2037
+ });
2038
+ check("string count '1' selects 'other' (not 'one') but interpolates '1'",
2039
+ i.t("items", { count: "1" }) === "1 items");
2040
+ check("string count '5' selects 'other' and interpolates '5'",
2041
+ i.t("items", { count: "5" }) === "5 items");
2042
+ // A boolean count is likewise non-numeric → other category.
2043
+ check("boolean count is non-numeric → 'other' category",
2044
+ i.t("items", { count: true }) === "true items");
2045
+ }
2046
+
2047
+ // tn()/to() merge the numeric count arg LAST into a copy of the caller vars, so
2048
+ // the count argument authoritatively wins over any `count` key the caller also
2049
+ // put in vars — the plural category tracks the argument, not the stray var.
2050
+ function testTnCountArgOverridesVarsCount() {
2051
+ var i = b.i18n.create({
2052
+ defaultLocale: "en",
2053
+ locales: ["en"],
2054
+ translations: { en: { items: { one: "{count} item", other: "{count} items" } } },
2055
+ });
2056
+ check("tn(): count arg (5) overrides vars.count (999) for selection + render",
2057
+ i.tn("items", 5, { count: 999 }) === "5 items");
2058
+ check("tn(): count arg (1) yields the 'one' category despite vars.count 999",
2059
+ i.tn("items", 1, { count: 999 }) === "1 item");
2060
+ }
2061
+
2062
+ // The interpolator trims whitespace inside the placeholder, so `{ name }`
2063
+ // resolves the `name` var (and, in strict mode, a genuinely-missing var still
2064
+ // throws referencing the trimmed name).
2065
+ function testInterpolationTrimsPlaceholderWhitespace() {
2066
+ var i = b.i18n.create({
2067
+ defaultLocale: "en",
2068
+ locales: ["en"],
2069
+ translations: { en: { hi: "Hi { name }!", tabbed: "{\tkey\t}" } },
2070
+ });
2071
+ check("placeholder with surrounding spaces resolves the trimmed var",
2072
+ i.t("hi", { name: "Bob" }) === "Hi Bob!");
2073
+ check("placeholder with surrounding tabs resolves the trimmed var",
2074
+ i.t("tabbed", { key: "V" }) === "V");
2075
+
2076
+ var iStrict = b.i18n.create({
2077
+ defaultLocale: "en",
2078
+ locales: ["en"],
2079
+ interpolation: { strict: true },
2080
+ translations: { en: { hi: "Hi { name }!" } },
2081
+ });
2082
+ var threw = false;
2083
+ try { iStrict.t("hi", { other: "x" }); } catch (_e) { threw = true; }
2084
+ check("strict mode still throws on a genuinely-missing trimmed var", threw);
2085
+ }
2086
+
2087
+ // dir() with no callerOpts resolves the CURRENT locale, so it tracks setLocale()
2088
+ // mutations — flipping to an RTL language flips the reported direction.
2089
+ function testDirReflectsCurrentLocaleAfterSetLocale() {
2090
+ var i = b.i18n.create({
2091
+ defaultLocale: "en",
2092
+ locales: ["en", "ar"],
2093
+ });
2094
+ check("dir() defaults to ltr under the initial en locale", i.dir() === "ltr");
2095
+ i.setLocale("ar");
2096
+ check("dir() with no opts reflects the RTL current locale after setLocale",
2097
+ i.dir() === "rtl");
2098
+ i.setLocale("en");
2099
+ check("dir() flips back to ltr after setLocale('en')", i.dir() === "ltr");
2100
+ }
2101
+
2102
+ // A resolver that returns a non-string value (a number, an object) is not a
2103
+ // usable locale: _isValidBcp47 rejects the non-string, so negotiation falls
2104
+ // through to Accept-Language rather than coercing the junk value.
2105
+ function testMiddlewareResolverNonStringReturn() {
2106
+ var i = b.i18n.create({
2107
+ defaultLocale: "en",
2108
+ locales: ["en", "es"],
2109
+ translations: { en: { greet: "Hello" }, es: { greet: "Hola" } },
2110
+ });
2111
+
2112
+ var mwNum = i.middleware({ resolver: function () { return 42; } });
2113
+ var reqNum = _mockReq();
2114
+ reqNum.headers = { "accept-language": "es" };
2115
+ mwNum(reqNum, _mockRes(), function () {});
2116
+ check("resolver returning a number falls through to header negotiation",
2117
+ reqNum.locale === "es");
2118
+
2119
+ var mwObj = i.middleware({ resolver: function () { return { lang: "es" }; } });
2120
+ var reqObj = _mockReq();
2121
+ reqObj.headers = { "accept-language": "es" };
2122
+ mwObj(reqObj, _mockRes(), function () {});
2123
+ check("resolver returning an object falls through to header negotiation",
2124
+ reqObj.locale === "es");
2125
+ }
2126
+
2127
+ // The explicit-source readers (query param, cookie) require a STRING value; a
2128
+ // non-string (a number, an array) is ignored — an attacker-controlled request
2129
+ // field of the wrong shape can never coerce the negotiated locale, and never
2130
+ // crashes the middleware. Negotiation falls back to Accept-Language.
2131
+ function testMiddlewareNonStringExplicitSourcesIgnored() {
2132
+ var i = b.i18n.create({
2133
+ defaultLocale: "en",
2134
+ locales: ["en", "es"],
2135
+ translations: { en: { greet: "Hello" }, es: { greet: "Hola" } },
2136
+ });
2137
+
2138
+ var reqNumQuery = _mockReq();
2139
+ reqNumQuery.headers = { "accept-language": "es" };
2140
+ reqNumQuery.query = { lang: 42 };
2141
+ i.middleware()(reqNumQuery, _mockRes(), function () {});
2142
+ check("numeric ?lang is ignored → header negotiation",
2143
+ reqNumQuery.locale === "es");
2144
+
2145
+ var reqArrQuery = _mockReq();
2146
+ reqArrQuery.headers = { "accept-language": "es" };
2147
+ reqArrQuery.query = { lang: ["es", "fr"] };
2148
+ i.middleware()(reqArrQuery, _mockRes(), function () {});
2149
+ check("array ?lang (duplicate query keys) is ignored → header negotiation",
2150
+ reqArrQuery.locale === "es");
2151
+
2152
+ var reqNumCookie = _mockReq();
2153
+ reqNumCookie.headers = { "accept-language": "es" };
2154
+ reqNumCookie.cookies = { pref: 5 };
2155
+ i.middleware({ cookieName: "pref" })(reqNumCookie, _mockRes(), function () {});
2156
+ check("non-string cookie value is ignored → header negotiation",
2157
+ reqNumCookie.locale === "es");
2158
+ }
1007
2159
 
1008
2160
  if (require.main === module) {
1009
2161
  run().then(