@blamejs/blamejs-shop 0.5.12 → 0.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (521) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +632 -416
  4. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
  5. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
  6. package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
  7. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  8. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
  9. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
  10. package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
  11. package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
  12. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
  13. package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
  14. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
  15. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  16. package/lib/vendor/blamejs/.gitignore +2 -0
  17. package/lib/vendor/blamejs/CHANGELOG.md +122 -0
  18. package/lib/vendor/blamejs/NOTICE +26 -1
  19. package/lib/vendor/blamejs/SECURITY.md +1 -1
  20. package/lib/vendor/blamejs/api-snapshot.json +207 -5
  21. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
  22. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
  25. package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
  26. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  27. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
  28. package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
  29. package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
  30. package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
  31. package/lib/vendor/blamejs/index.js +6 -0
  32. package/lib/vendor/blamejs/lib/a2a.js +4 -4
  33. package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
  34. package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
  35. package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
  36. package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
  37. package/lib/vendor/blamejs/lib/archive-read.js +8 -0
  38. package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
  39. package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
  40. package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
  41. package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
  42. package/lib/vendor/blamejs/lib/audit.js +71 -8
  43. package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
  44. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
  45. package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
  46. package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
  47. package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
  48. package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
  49. package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
  50. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
  51. package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
  52. package/lib/vendor/blamejs/lib/backup/index.js +16 -5
  53. package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
  54. package/lib/vendor/blamejs/lib/base32.js +21 -0
  55. package/lib/vendor/blamejs/lib/break-glass.js +19 -10
  56. package/lib/vendor/blamejs/lib/bundler.js +5 -1
  57. package/lib/vendor/blamejs/lib/cache-status.js +3 -7
  58. package/lib/vendor/blamejs/lib/calendar.js +21 -1
  59. package/lib/vendor/blamejs/lib/cbor.js +12 -1
  60. package/lib/vendor/blamejs/lib/cert.js +29 -11
  61. package/lib/vendor/blamejs/lib/cli.js +94 -24
  62. package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
  63. package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
  64. package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
  65. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
  66. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
  67. package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
  68. package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
  69. package/lib/vendor/blamejs/lib/content-digest.js +2 -1
  70. package/lib/vendor/blamejs/lib/cookies.js +13 -3
  71. package/lib/vendor/blamejs/lib/cose.js +31 -16
  72. package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
  73. package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
  74. package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
  75. package/lib/vendor/blamejs/lib/crypto.js +314 -19
  76. package/lib/vendor/blamejs/lib/csp.js +11 -3
  77. package/lib/vendor/blamejs/lib/daemon.js +270 -24
  78. package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
  79. package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
  80. package/lib/vendor/blamejs/lib/db-query.js +34 -7
  81. package/lib/vendor/blamejs/lib/db.js +18 -6
  82. package/lib/vendor/blamejs/lib/dbsc.js +17 -0
  83. package/lib/vendor/blamejs/lib/dev.js +21 -2
  84. package/lib/vendor/blamejs/lib/dsr.js +157 -102
  85. package/lib/vendor/blamejs/lib/external-db.js +41 -2
  86. package/lib/vendor/blamejs/lib/file-upload.js +25 -7
  87. package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
  88. package/lib/vendor/blamejs/lib/forms.js +113 -27
  89. package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
  90. package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
  91. package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
  92. package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
  93. package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
  94. package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
  95. package/lib/vendor/blamejs/lib/guard-html.js +26 -53
  96. package/lib/vendor/blamejs/lib/guard-image.js +24 -5
  97. package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
  98. package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
  99. package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
  100. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
  101. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
  102. package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
  105. package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
  106. package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
  107. package/lib/vendor/blamejs/lib/guard-time.js +1 -1
  108. package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
  109. package/lib/vendor/blamejs/lib/html-balance.js +3 -3
  110. package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
  111. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
  112. package/lib/vendor/blamejs/lib/http-client.js +39 -7
  113. package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
  114. package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
  115. package/lib/vendor/blamejs/lib/i18n.js +35 -21
  116. package/lib/vendor/blamejs/lib/incident-report.js +8 -1
  117. package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
  118. package/lib/vendor/blamejs/lib/json-path.js +23 -1
  119. package/lib/vendor/blamejs/lib/jwk.js +20 -3
  120. package/lib/vendor/blamejs/lib/link-header.js +2 -1
  121. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
  123. package/lib/vendor/blamejs/lib/log-stream.js +8 -3
  124. package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
  125. package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
  126. package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
  128. package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
  129. package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
  130. package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
  131. package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
  132. package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
  133. package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
  134. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
  136. package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
  137. package/lib/vendor/blamejs/lib/mail.js +15 -5
  138. package/lib/vendor/blamejs/lib/metrics.js +268 -63
  139. package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
  140. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
  141. package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
  142. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
  143. package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
  144. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
  145. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
  146. package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
  147. package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
  148. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
  149. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
  150. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
  151. package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
  152. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
  153. package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
  154. package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
  155. package/lib/vendor/blamejs/lib/network-dns.js +21 -2
  156. package/lib/vendor/blamejs/lib/network-tls.js +69 -7
  157. package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
  158. package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
  159. package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
  160. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
  161. package/lib/vendor/blamejs/lib/outbox.js +1 -1
  162. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
  163. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
  164. package/lib/vendor/blamejs/lib/permissions.js +6 -3
  165. package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
  166. package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
  167. package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
  168. package/lib/vendor/blamejs/lib/pubsub.js +20 -9
  169. package/lib/vendor/blamejs/lib/queue-local.js +8 -1
  170. package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
  171. package/lib/vendor/blamejs/lib/redact.js +54 -0
  172. package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
  173. package/lib/vendor/blamejs/lib/restore.js +19 -0
  174. package/lib/vendor/blamejs/lib/retention.js +12 -4
  175. package/lib/vendor/blamejs/lib/router.js +60 -6
  176. package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
  177. package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
  178. package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
  179. package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
  180. package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
  181. package/lib/vendor/blamejs/lib/safe-object.js +80 -0
  182. package/lib/vendor/blamejs/lib/safe-path.js +52 -4
  183. package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
  184. package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
  185. package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
  186. package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
  187. package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
  188. package/lib/vendor/blamejs/lib/scheduler.js +8 -1
  189. package/lib/vendor/blamejs/lib/security-assert.js +6 -6
  190. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
  191. package/lib/vendor/blamejs/lib/self-update.js +517 -87
  192. package/lib/vendor/blamejs/lib/server-timing.js +2 -4
  193. package/lib/vendor/blamejs/lib/session.js +34 -12
  194. package/lib/vendor/blamejs/lib/sql.js +15 -1
  195. package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
  196. package/lib/vendor/blamejs/lib/static.js +55 -13
  197. package/lib/vendor/blamejs/lib/storage.js +8 -2
  198. package/lib/vendor/blamejs/lib/subject.js +6 -1
  199. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
  200. package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
  201. package/lib/vendor/blamejs/lib/tsa.js +34 -13
  202. package/lib/vendor/blamejs/lib/uri-template.js +8 -1
  203. package/lib/vendor/blamejs/lib/vault/index.js +13 -0
  204. package/lib/vendor/blamejs/lib/vc.js +44 -5
  205. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
  206. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
  207. package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
  208. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
  209. package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
  210. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
  212. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
  213. package/lib/vendor/blamejs/lib/watcher.js +89 -17
  214. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
  215. package/lib/vendor/blamejs/lib/webhook.js +12 -2
  216. package/lib/vendor/blamejs/lib/ws-client.js +32 -1
  217. package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
  218. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
  219. package/lib/vendor/blamejs/package-lock.json +2 -2
  220. package/lib/vendor/blamejs/package.json +1 -1
  221. package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
  222. package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
  223. package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
  224. package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
  225. package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
  226. package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
  227. package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
  228. package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
  229. package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
  230. package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
  231. package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
  232. package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
  233. package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
  234. package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
  235. package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
  236. package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
  237. package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
  238. package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
  239. package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
  240. package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
  241. package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
  242. package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
  243. package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
  244. package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
  245. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
  246. package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
  247. package/lib/vendor/blamejs/socket.yml +94 -0
  248. package/lib/vendor/blamejs/test/00-primitives.js +605 -0
  249. package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
  250. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
  251. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
  252. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
  253. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
  254. package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
  255. package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
  256. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
  257. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
  258. package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
  259. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
  262. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
  268. package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
  284. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
  293. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
  294. package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
  302. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
  307. package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
  315. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
  317. package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
  318. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
  319. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
  320. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
  321. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
  322. package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
  323. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
  324. package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
  325. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
  326. package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
  327. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
  328. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
  329. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
  330. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
  331. package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
  334. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
  335. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
  336. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
  337. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
  341. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
  342. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
  346. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
  347. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
  348. package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
  349. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
  376. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
  388. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
  389. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
  390. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
  391. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
  392. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
  393. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
  395. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
  396. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
  397. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
  398. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
  399. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
  400. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
  401. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
  402. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
  403. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
  404. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
  405. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
  406. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
  407. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
  408. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
  409. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
  410. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
  411. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
  412. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
  413. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
  414. package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
  415. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
  416. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
  417. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
  418. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
  419. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
  420. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
  421. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
  422. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
  423. package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
  424. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
  425. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
  426. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
  427. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
  428. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
  429. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
  430. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
  431. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
  432. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
  433. package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
  434. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
  435. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
  436. package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
  437. package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
  438. package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
  439. package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
  440. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
  441. package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
  442. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
  443. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
  444. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
  445. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
  446. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
  447. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
  448. package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
  449. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
  450. package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
  451. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
  452. package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
  453. package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
  454. package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
  455. package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
  456. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
  457. package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
  458. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
  459. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
  460. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
  461. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
  462. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
  463. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
  464. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
  465. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
  466. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
  467. package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
  468. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
  469. package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
  470. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
  471. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
  472. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
  473. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
  474. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
  475. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
  476. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
  477. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
  478. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
  479. package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
  480. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
  481. package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
  482. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
  483. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
  484. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
  485. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
  486. package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
  487. package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
  488. package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
  489. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
  490. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
  491. package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
  492. package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
  493. package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
  494. package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
  495. package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
  496. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
  497. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
  498. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
  499. package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
  500. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
  501. package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
  502. package/lib/vendor/blamejs/test/smoke.js +2 -0
  503. package/package.json +1 -1
  504. package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
  505. package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
  506. package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
  507. package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
  508. package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
  509. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
  510. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
  511. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
  512. package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
  513. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
  514. package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
  515. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
  516. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
  517. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
  518. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
  519. package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
  520. package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
  521. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
@@ -0,0 +1,1032 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) blamejs contributors
3
+ "use strict";
4
+ /**
5
+ * cluster — leader election + write-side gates.
6
+ *
7
+ * Covers b.cluster.externalDbBackend (the wired shared-DB handle getter)
8
+ * and b.cluster.onTransition (role-transition callback registration +
9
+ * firing) on the happy path, plus the full error / adversarial /
10
+ * defensive surface:
11
+ *
12
+ * - b.cluster.init config-time rejections (missing nodeId, sub-minimum
13
+ * lease/heartbeat, heartbeat >= lease, bad role, rejected endpoint,
14
+ * malformed expectedVaultKeyFp, un-declared rotation blessing,
15
+ * non-boolean acceptVaultKeyRotation, no provider/backend, double
16
+ * init).
17
+ * - The heartbeat state machine driven through a controllable custom
18
+ * election provider: acquire failure, renew success, LEASE_LOST
19
+ * takeover, transient renew error, follower re-acquisition.
20
+ * - b.cluster.currentLeader + b.cluster.discoveryHandler across the
21
+ * single-node fallback, a live leader, no-leader, and provider-error
22
+ * paths.
23
+ * - Boot-time chain-tip rollback detection (counter regression,
24
+ * row-hash substitution, non-missing-table re-throw, empty-tip skip,
25
+ * consistent-chain pass) against a live in-process SQLite backend.
26
+ * - Vault-key consistency: cross-node drift refusal, rotation-blessing
27
+ * mismatch, rotation adoption, the fail-closed CLUSTER_STATE_MISSING
28
+ * and concurrent-divergent-adopt guards, the structured
29
+ * missing-relation code/errno classification, and the vault-not-
30
+ * initialized gates-only skip.
31
+ *
32
+ * Run standalone: `node test/layer-0-primitives/cluster.test.js`
33
+ * Or via smoke: `node test/smoke.js`
34
+ */
35
+
36
+ var helpers = require("../helpers");
37
+ var b = helpers.b;
38
+ var fs = helpers.fs;
39
+ var os = helpers.os;
40
+ var path = helpers.path;
41
+ var check = helpers.check;
42
+ var setupTestDb = helpers.setupTestDb;
43
+ var teardownTestDb = helpers.teardownTestDb;
44
+ var _makeSqliteDriver = helpers._makeSqliteDriver;
45
+ var _mockReq = helpers._mockReq;
46
+ var _mockRes = helpers._mockRes;
47
+ var C = b.constants;
48
+
49
+ // ---- shared test doubles ----
50
+
51
+ // A controllable leader-election provider. cluster.init accepts a custom
52
+ // `provider` (a documented opt), so this drives the real heartbeat state
53
+ // machine in-process with zero DB dependency — every acquire / renew /
54
+ // release / currentLeader outcome is scripted through `ctl`.
55
+ function _makeStubProvider() {
56
+ var ctl = {
57
+ acquireResult: "lease", // "lease" | null | "throw"
58
+ renewMode: "ok", // "ok" | "lost" | "transient"
59
+ releaseMode: "ok", // "ok" | "throw"
60
+ currentLeaderResult: null, // object | null | "throw"
61
+ fencing: 0,
62
+ ensureSchemaCalls: 0,
63
+ };
64
+ var provider = {
65
+ ensureSchema: async function () { ctl.ensureSchemaCalls += 1; },
66
+ acquireLease: async function (nodeId, ttlMs, opts) {
67
+ if (ctl.acquireResult === "throw") throw new Error("stub acquire boom");
68
+ if (ctl.acquireResult === null) return null;
69
+ ctl.fencing += 1;
70
+ return {
71
+ nodeId: nodeId,
72
+ leaseId: "lease-" + ctl.fencing,
73
+ acquiredAt: Date.now(),
74
+ expiresAt: Date.now() + ttlMs,
75
+ fencingToken: ctl.fencing,
76
+ endpoint: (opts && opts.endpoint) || null,
77
+ };
78
+ },
79
+ renewLease: async function (lease, opts) {
80
+ if (ctl.renewMode === "lost") {
81
+ var e = new Error("stub lease taken over");
82
+ e.code = "LEASE_LOST";
83
+ throw e;
84
+ }
85
+ if (ctl.renewMode === "transient") throw new Error("stub transient renew boom");
86
+ return Object.assign({}, lease, {
87
+ expiresAt: Date.now() + C.TIME.seconds(30),
88
+ endpoint: (opts && "endpoint" in opts) ? opts.endpoint : (lease.endpoint || null),
89
+ });
90
+ },
91
+ releaseLease: async function () {
92
+ if (ctl.releaseMode === "throw") throw new Error("stub release boom");
93
+ },
94
+ currentLeader: async function () {
95
+ if (ctl.currentLeaderResult === "throw") throw new Error("stub currentLeader boom");
96
+ return ctl.currentLeaderResult;
97
+ },
98
+ };
99
+ return { provider: provider, ctl: ctl };
100
+ }
101
+
102
+ // Execute one raw statement against the in-process SQLite coordination DB
103
+ // through the same driver handle cluster.js queries, so a seeded tip /
104
+ // state row is visible to the boot-time checks.
105
+ async function _seed(driver, sqlText, params) {
106
+ var client = await driver.connect();
107
+ return driver.query(client, sqlText, params || []);
108
+ }
109
+
110
+ // Live SQLite coordination fixture: real vault (needed for the vault-key
111
+ // fingerprint) + a real external-db backend the boot-time checks run
112
+ // against. A stub election provider keeps the node a pinned follower so
113
+ // no lease-election writes get in the way of the check being exercised.
114
+ async function _coordFixture() {
115
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cluster-cov-"));
116
+ b.cluster._resetForTest();
117
+ await setupTestDb(tmpDir);
118
+ var dbPath = path.join(tmpDir, "ha-coord.db");
119
+ var driver = _makeSqliteDriver(dbPath);
120
+ b.externalDb.init({
121
+ backends: { ops: { connect: driver.connect, query: driver.query, close: driver.close } },
122
+ });
123
+ return {
124
+ tmpDir: tmpDir,
125
+ driver: driver,
126
+ teardown: async function () {
127
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
128
+ try { await b.externalDb.shutdown(); } catch (_e) { /* best-effort */ }
129
+ try { driver._close(); } catch (_e) { /* best-effort */ }
130
+ await teardownTestDb(tmpDir);
131
+ },
132
+ };
133
+ }
134
+
135
+ // Init as a pinned follower against a custom backend/provider pair, so the
136
+ // boot-time rollback + vault-key checks run but no leader election fires.
137
+ async function _initFollowerAgainst(backendName, provider) {
138
+ await b.cluster.init({
139
+ nodeId: "cov-follower",
140
+ role: "follower",
141
+ provider: provider,
142
+ externalDbBackend: backendName,
143
+ dialect: "sqlite",
144
+ leaseTtl: C.TIME.seconds(30),
145
+ heartbeatInterval: C.TIME.seconds(15),
146
+ });
147
+ }
148
+
149
+ // A 128-char lowercase-hex string (a well-formed SHA3-512 fingerprint
150
+ // shape) that is not this node's real vault-key fingerprint.
151
+ function _bogusFp(ch) { return String(ch).repeat(128); }
152
+
153
+ // ---- existing coverage: getter + transition happy path ----
154
+
155
+ async function testExternalDbBackendAndOnTransition() {
156
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cluster-"));
157
+ b.cluster._resetForTest();
158
+ await setupTestDb(tmpDir);
159
+
160
+ var dbPath = path.join(tmpDir, "ha-coord.db");
161
+ var driver = _makeSqliteDriver(dbPath);
162
+ b.externalDb.init({
163
+ backends: {
164
+ ops: { connect: driver.connect, query: driver.query, close: driver.close },
165
+ },
166
+ });
167
+
168
+ var events = [];
169
+ var order = [];
170
+ try {
171
+ // Pre-init contract: nothing wired yet.
172
+ check("cluster.externalDbBackend null before init", b.cluster.externalDbBackend() === null);
173
+ check("cluster.isClusterMode false before init", b.cluster.isClusterMode() === false);
174
+
175
+ // Config-time tier: a non-function handler throws synchronously.
176
+ var badThrew = null;
177
+ try { b.cluster.onTransition("not-a-fn"); } catch (e) { badThrew = e; }
178
+ check("cluster.onTransition rejects a non-function handler",
179
+ badThrew && badThrew.code === "INVALID_HANDLER");
180
+
181
+ // Register two handlers BEFORE init; both must fire in registration order.
182
+ b.cluster.onTransition(function (ev) { order.push("a"); events.push(ev); });
183
+ b.cluster.onTransition(function (ev) { order.push("b"); });
184
+
185
+ await b.cluster.init({
186
+ nodeId: "cluster-domain-node",
187
+ externalDbBackend: "ops",
188
+ dialect: "sqlite",
189
+ leaseTtl: C.TIME.seconds(30),
190
+ heartbeatInterval: C.TIME.seconds(10),
191
+ });
192
+
193
+ // externalDbBackend now returns the wired handle name.
194
+ check("cluster.externalDbBackend returns the configured backend after init",
195
+ b.cluster.externalDbBackend() === "ops");
196
+ check("cluster.isClusterMode true once wired", b.cluster.isClusterMode() === true);
197
+
198
+ // Single node → immediate leader → a lease-acquired transition fired.
199
+ await helpers.waitUntil(function () {
200
+ return events.some(function (e) { return e.kind === "lease-acquired"; });
201
+ }, { timeoutMs: 5000, label: "cluster.onTransition: lease-acquired fired" });
202
+ var acq = events.find(function (e) { return e.kind === "lease-acquired"; });
203
+ check("transition event carries the nodeId", acq.nodeId === "cluster-domain-node");
204
+ check("transition event carries a numeric fencingToken",
205
+ typeof acq.fencingToken === "number" && acq.fencingToken >= 1);
206
+ check("transition event carries a timestamp", typeof acq.at === "number");
207
+ check("both handlers ran, in registration order",
208
+ order.length >= 2 && order[0] === "a" && order[1] === "b");
209
+
210
+ // shutdown releases the lease + emits a lease-released transition.
211
+ await b.cluster.shutdown();
212
+ await helpers.waitUntil(function () {
213
+ return events.some(function (e) { return e.kind === "lease-released"; });
214
+ }, { timeoutMs: 5000, label: "cluster.onTransition: lease-released fired" });
215
+ check("cluster.externalDbBackend null again after shutdown",
216
+ b.cluster.externalDbBackend() === null);
217
+ } finally {
218
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
219
+ try { await b.externalDb.shutdown(); } catch (_e) { /* best-effort */ }
220
+ try { driver._close(); } catch (_e) { /* best-effort */ }
221
+ await teardownTestDb(tmpDir);
222
+ }
223
+ }
224
+
225
+ // ---- init config-time validation (THROW tier) ----
226
+
227
+ async function _expectInitThrow(label, opts, expectedCode) {
228
+ b.cluster._resetForTest();
229
+ var threw = null;
230
+ try { await b.cluster.init(opts); } catch (e) { threw = e; }
231
+ check(label + " throws", threw !== null);
232
+ check(label + " code=" + expectedCode, threw && threw.code === expectedCode);
233
+ b.cluster._resetForTest();
234
+ }
235
+
236
+ async function testInitConfigValidation() {
237
+ // Missing nodeId (explicit empty opts, and the no-argument form).
238
+ await _expectInitThrow("init without nodeId", {}, "INVALID_CONFIG");
239
+ await _expectInitThrow("init with no opts object", undefined, "INVALID_CONFIG");
240
+
241
+ // leaseTtl below the 10s floor.
242
+ await _expectInitThrow("init leaseTtl below floor",
243
+ { nodeId: "n", leaseTtl: C.TIME.seconds(5), externalDbBackend: "x" }, "INVALID_TTL");
244
+
245
+ // heartbeat below the 1s floor.
246
+ await _expectInitThrow("init heartbeat below floor",
247
+ { nodeId: "n", heartbeatInterval: 500, externalDbBackend: "x" }, "INVALID_HEARTBEAT");
248
+
249
+ // heartbeat >= leaseTtl (must fit comfortably inside the lease).
250
+ await _expectInitThrow("init heartbeat >= leaseTtl",
251
+ { nodeId: "n", leaseTtl: C.TIME.seconds(10), heartbeatInterval: C.TIME.seconds(10),
252
+ externalDbBackend: "x" }, "INVALID_HEARTBEAT");
253
+
254
+ // Role outside leader/follower.
255
+ await _expectInitThrow("init with unknown role",
256
+ { nodeId: "n", role: "observer", externalDbBackend: "x" }, "INVALID_ROLE");
257
+
258
+ // Endpoint rejected — cleartext HTTP under the HTTPS-only default.
259
+ await _expectInitThrow("init with non-TLS endpoint",
260
+ { nodeId: "n", endpoint: "http://plain.internal:8080", externalDbBackend: "x" },
261
+ "INVALID_ENDPOINT");
262
+
263
+ // expectedVaultKeyFp that isn't a 128-char lowercase-hex fingerprint.
264
+ await _expectInitThrow("init with malformed expectedVaultKeyFp",
265
+ { nodeId: "n", acceptVaultKeyRotation: true, expectedVaultKeyFp: "not-a-fingerprint",
266
+ externalDbBackend: "x" }, "INVALID_CONFIG");
267
+
268
+ // expectedVaultKeyFp blessed but rotation acceptance never enabled.
269
+ await _expectInitThrow("init blessing a fingerprint without acceptVaultKeyRotation",
270
+ { nodeId: "n", expectedVaultKeyFp: _bogusFp("a"), externalDbBackend: "x" },
271
+ "INVALID_CONFIG");
272
+
273
+ // Non-boolean acceptVaultKeyRotation.
274
+ await _expectInitThrow("init with non-boolean acceptVaultKeyRotation",
275
+ { nodeId: "n", acceptVaultKeyRotation: "yes", externalDbBackend: "x" }, "INVALID_CONFIG");
276
+
277
+ // Neither a custom provider nor an externalDbBackend.
278
+ await _expectInitThrow("init without provider or externalDbBackend",
279
+ { nodeId: "n" }, "INVALID_CONFIG");
280
+
281
+ // Double init — second call refused.
282
+ b.cluster._resetForTest();
283
+ var s = _makeStubProvider();
284
+ var doubleThrew = null;
285
+ try {
286
+ await b.cluster.init({
287
+ nodeId: "double-node", provider: s.provider, role: "follower",
288
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
289
+ });
290
+ try {
291
+ await b.cluster.init({ nodeId: "double-node-2", provider: s.provider, role: "follower" });
292
+ } catch (e) { doubleThrew = e; }
293
+ check("second cluster.init is refused", doubleThrew && doubleThrew.code === "ALREADY_INITIALIZED");
294
+ } finally {
295
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
296
+ b.cluster._resetForTest();
297
+ }
298
+ }
299
+
300
+ // ---- sync surface: getters, requireLeader, endpoint validation, reset ----
301
+
302
+ async function testSyncSurfaceAndGetters() {
303
+ b.cluster._resetForTest();
304
+
305
+ // Permanent-leader fallback before init.
306
+ check("isLeader true before init (permanent-leader fallback)", b.cluster.isLeader() === true);
307
+ check("currentNodeId single-node before init",
308
+ b.cluster.currentNodeId() === "single-node-local");
309
+ check("fencingToken 0 before init", b.cluster.fencingToken() === 0);
310
+ check("dialect null before init", b.cluster.dialect() === null);
311
+ // NotLeaderError with no message falls back to its default text.
312
+ var defErr = new b.cluster.NotLeaderError();
313
+ check("NotLeaderError default message", /not leader/.test(defErr.message));
314
+ check("endpoint null before init", b.cluster.endpoint() === null);
315
+ var preThrew = null;
316
+ try { b.cluster.requireLeader(); } catch (e) { preThrew = e; }
317
+ check("requireLeader does not throw before init", preThrew === null);
318
+
319
+ var s = _makeStubProvider();
320
+ s.ctl.acquireResult = "lease";
321
+ var transitions = [];
322
+ try {
323
+ await b.cluster.init({
324
+ nodeId: "getter-node",
325
+ role: "leader",
326
+ provider: s.provider,
327
+ dialect: "postgres",
328
+ endpoint: "https://getter.internal:8443",
329
+ leaseTtl: C.TIME.seconds(30),
330
+ heartbeatInterval: C.TIME.seconds(15),
331
+ onTransition: function (ev) { transitions.push(ev); },
332
+ });
333
+
334
+ check("isLeader true after acquiring a lease", b.cluster.isLeader() === true);
335
+ check("fencingToken reflects the lease token", b.cluster.fencingToken() >= 1);
336
+ check("dialect returns the configured dialect", b.cluster.dialect() === "postgres");
337
+ check("endpoint returns the validated endpoint",
338
+ b.cluster.endpoint() === "https://getter.internal:8443");
339
+ check("onTransition supplied at init fired on acquire",
340
+ transitions.some(function (e) { return e.kind === "lease-acquired"; }));
341
+
342
+ // requireLeader passes while leader.
343
+ var leaderThrew = null;
344
+ try { b.cluster.requireLeader(); } catch (e) { leaderThrew = e; }
345
+ check("requireLeader passes while holding the lease", leaderThrew === null);
346
+
347
+ // shutdown → terminated: never leader again until a fresh init.
348
+ await b.cluster.shutdown();
349
+ check("isLeader false after shutdown (terminated)", b.cluster.isLeader() === false);
350
+ var postThrew = null;
351
+ try { b.cluster.requireLeader(); } catch (e) { postThrew = e; }
352
+ check("requireLeader throws NotLeaderError after shutdown",
353
+ postThrew instanceof b.cluster.NotLeaderError);
354
+ check("post-shutdown NotLeaderError notes the uninitialized state",
355
+ postThrew && /not initialized/.test(postThrew.message));
356
+ check("NotLeaderError carries a 503 status", postThrew && postThrew.statusCode === 503);
357
+ check("NotLeaderError carries the cluster/not-leader flags",
358
+ postThrew && postThrew.code === "NOT_LEADER" &&
359
+ postThrew.isNotLeaderError === true && postThrew.isClusterError === true);
360
+ } finally {
361
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
362
+ b.cluster._resetForTest();
363
+ }
364
+
365
+ // Follower: initialized but never holds the lease → requireLeader throws
366
+ // WITHOUT the "(cluster not initialized)" suffix.
367
+ b.cluster._resetForTest();
368
+ var f = _makeStubProvider();
369
+ try {
370
+ await b.cluster.init({
371
+ nodeId: "follower-node", role: "follower", provider: f.provider,
372
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
373
+ });
374
+ check("follower is not leader", b.cluster.isLeader() === false);
375
+ var fThrew = null;
376
+ try { b.cluster.requireLeader(); } catch (e) { fThrew = e; }
377
+ check("follower requireLeader throws NOT_LEADER", fThrew && fThrew.code === "NOT_LEADER");
378
+ check("follower NotLeaderError omits the uninitialized suffix",
379
+ fThrew && !/not initialized/.test(fThrew.message));
380
+
381
+ // _resetForTest with a running heartbeat timer stops it cleanly.
382
+ b.cluster._resetForTest();
383
+ check("reset clears cluster mode", b.cluster.isClusterMode() === false);
384
+ } finally {
385
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
386
+ b.cluster._resetForTest();
387
+ }
388
+
389
+ // Endpoint opt-out: cleartext accepted when allowedProtocols permits it.
390
+ b.cluster._resetForTest();
391
+ var h = _makeStubProvider();
392
+ try {
393
+ await b.cluster.init({
394
+ nodeId: "cleartext-node", role: "follower", provider: h.provider,
395
+ endpoint: "http://internal.cleartext:8080",
396
+ allowedProtocols: b.safeUrl.ALLOW_HTTP_ALL,
397
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
398
+ });
399
+ check("cleartext endpoint accepted under ALLOW_HTTP_ALL",
400
+ b.cluster.endpoint() === "http://internal.cleartext:8080");
401
+ } finally {
402
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
403
+ b.cluster._resetForTest();
404
+ }
405
+ }
406
+
407
+ // ---- heartbeat state machine ----
408
+
409
+ async function testHeartbeatStateMachine() {
410
+ // (1) Acquire failure at init is caught — node stays a non-leader and
411
+ // init still completes.
412
+ b.cluster._resetForTest();
413
+ var s1 = _makeStubProvider();
414
+ s1.ctl.acquireResult = "throw";
415
+ try {
416
+ await b.cluster.init({
417
+ nodeId: "hb-acq-fail", role: "leader", provider: s1.provider,
418
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
419
+ });
420
+ check("acquire failure leaves the node non-leader", b.cluster.isLeader() === false);
421
+ check("acquire failure still completes init", b.cluster.isClusterMode() === false);
422
+ } finally {
423
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
424
+ b.cluster._resetForTest();
425
+ }
426
+
427
+ // (2) Renew success on the next heartbeat keeps the lease.
428
+ b.cluster._resetForTest();
429
+ var s2 = _makeStubProvider();
430
+ s2.ctl.acquireResult = "lease";
431
+ try {
432
+ await b.cluster.init({
433
+ nodeId: "hb-renew", role: "leader", provider: s2.provider,
434
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
435
+ });
436
+ check("holds lease after initial acquire", b.cluster.isLeader() === true);
437
+ var tokenBefore = b.cluster.fencingToken();
438
+ await b.cluster._heartbeatNowForTest();
439
+ check("renew keeps the node leader", b.cluster.isLeader() === true);
440
+ check("renew does not bump the fencing token", b.cluster.fencingToken() === tokenBefore);
441
+ } finally {
442
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
443
+ b.cluster._resetForTest();
444
+ }
445
+
446
+ // (3) LEASE_LOST on renew → step down to follower + emit lease-lost.
447
+ b.cluster._resetForTest();
448
+ var s3 = _makeStubProvider();
449
+ s3.ctl.acquireResult = "lease";
450
+ var lostEvents = [];
451
+ try {
452
+ await b.cluster.init({
453
+ nodeId: "hb-lost", role: "leader", provider: s3.provider,
454
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
455
+ onTransition: function (ev) { lostEvents.push(ev); },
456
+ });
457
+ check("leader before lease loss", b.cluster.isLeader() === true);
458
+ s3.ctl.renewMode = "lost";
459
+ await b.cluster._heartbeatNowForTest();
460
+ check("lease loss steps the node down", b.cluster.isLeader() === false);
461
+ check("lease loss emits a lease-lost transition",
462
+ lostEvents.some(function (e) { return e.kind === "lease-lost"; }));
463
+ } finally {
464
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
465
+ b.cluster._resetForTest();
466
+ }
467
+
468
+ // (4) Transient renew error → lease preserved, retry next tick.
469
+ b.cluster._resetForTest();
470
+ var s4 = _makeStubProvider();
471
+ s4.ctl.acquireResult = "lease";
472
+ try {
473
+ await b.cluster.init({
474
+ nodeId: "hb-transient", role: "leader", provider: s4.provider,
475
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
476
+ });
477
+ s4.ctl.renewMode = "transient";
478
+ await b.cluster._heartbeatNowForTest();
479
+ check("transient renew error preserves the lease", b.cluster.isLeader() === true);
480
+ } finally {
481
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
482
+ b.cluster._resetForTest();
483
+ }
484
+
485
+ // (5) Follower re-acquisition path: no lease yet → heartbeat retries the
486
+ // acquire (jitter branch), succeeds, becomes leader.
487
+ b.cluster._resetForTest();
488
+ var s5 = _makeStubProvider();
489
+ s5.ctl.acquireResult = null; // initial acquire yields nothing
490
+ try {
491
+ await b.cluster.init({
492
+ nodeId: "hb-reacquire", role: "leader", provider: s5.provider,
493
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(1),
494
+ });
495
+ check("no lease after a null initial acquire", b.cluster.isLeader() === false);
496
+ s5.ctl.acquireResult = "lease";
497
+ await b.cluster._heartbeatNowForTest(); // !lease → jitter → re-acquire
498
+ check("heartbeat re-acquisition promotes the node", b.cluster.isLeader() === true);
499
+ } finally {
500
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
501
+ b.cluster._resetForTest();
502
+ }
503
+
504
+ // (5b) A throwing releaseLease on shutdown is caught — shutdown still
505
+ // completes and the node steps down.
506
+ b.cluster._resetForTest();
507
+ var s5b = _makeStubProvider();
508
+ s5b.ctl.acquireResult = "lease";
509
+ s5b.ctl.releaseMode = "throw";
510
+ await b.cluster.init({
511
+ nodeId: "hb-release-throws", role: "leader", provider: s5b.provider,
512
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
513
+ });
514
+ check("leader before a throwing-release shutdown", b.cluster.isLeader() === true);
515
+ var releaseThrew = null;
516
+ try { await b.cluster.shutdown(); } catch (e) { releaseThrew = e; }
517
+ check("shutdown swallows a releaseLease failure", releaseThrew === null);
518
+ check("node is not leader after a throwing-release shutdown", b.cluster.isLeader() === false);
519
+ b.cluster._resetForTest();
520
+
521
+ // (5c) A pinned follower's heartbeat never claims the lease.
522
+ b.cluster._resetForTest();
523
+ var s5c = _makeStubProvider();
524
+ s5c.ctl.acquireResult = "lease"; // would succeed IF a follower asked
525
+ try {
526
+ await b.cluster.init({
527
+ nodeId: "hb-follower", role: "follower", provider: s5c.provider,
528
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(1),
529
+ });
530
+ check("initialized follower reports fencingToken 0", b.cluster.fencingToken() === 0);
531
+ await b.cluster._heartbeatNowForTest(); // !lease → jitter → _tryAcquire → follower no-op
532
+ check("a follower heartbeat does not claim the lease", b.cluster.isLeader() === false);
533
+ check("no acquire is attempted for a pinned follower", s5c.ctl.fencing === 0);
534
+ } finally {
535
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
536
+ b.cluster._resetForTest();
537
+ }
538
+
539
+ // (6) Heartbeat after shutdown is a no-op (guarded on !initialized).
540
+ b.cluster._resetForTest();
541
+ var s6 = _makeStubProvider();
542
+ await b.cluster.init({
543
+ nodeId: "hb-after-shutdown", role: "follower", provider: s6.provider,
544
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
545
+ });
546
+ await b.cluster.shutdown();
547
+ var afterShutdownThrew = null;
548
+ try { await b.cluster._heartbeatNowForTest(); } catch (e) { afterShutdownThrew = e; }
549
+ check("heartbeat after shutdown is a no-op", afterShutdownThrew === null);
550
+ b.cluster._resetForTest();
551
+
552
+ // (7) A throwing transition handler is isolated — the next handler runs.
553
+ b.cluster._resetForTest();
554
+ var s7 = _makeStubProvider();
555
+ s7.ctl.acquireResult = "lease";
556
+ var goodRan = false;
557
+ try {
558
+ await b.cluster.init({
559
+ nodeId: "hb-throwing-handler", role: "leader", provider: s7.provider,
560
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
561
+ onTransition: function () { throw new Error("handler boom"); },
562
+ });
563
+ b.cluster.onTransition(function () { goodRan = true; });
564
+ // Force a fresh acquire transition via a lease-lost / re-acquire cycle.
565
+ s7.ctl.renewMode = "lost";
566
+ await b.cluster._heartbeatNowForTest(); // lease-lost (both handlers)
567
+ s7.ctl.renewMode = "ok";
568
+ await b.cluster._heartbeatNowForTest(); // re-acquire → lease-acquired
569
+ check("a throwing transition handler does not break the chain", goodRan === true);
570
+ } finally {
571
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
572
+ b.cluster._resetForTest();
573
+ }
574
+ }
575
+
576
+ // ---- currentLeader + discoveryHandler ----
577
+
578
+ async function _invokeDiscovery() {
579
+ var handler = b.cluster.discoveryHandler();
580
+ var req = _mockReq("GET", "/cluster/leader");
581
+ var res = _mockRes();
582
+ await handler(req, res);
583
+ var cap = res._captured();
584
+ return { status: cap.status, body: cap.body ? JSON.parse(cap.body) : null, headers: cap.headers };
585
+ }
586
+
587
+ async function testCurrentLeaderAndDiscovery() {
588
+ // Single-node fallback (init never called): synthetic leader record.
589
+ b.cluster._resetForTest();
590
+ var single = await b.cluster.currentLeader();
591
+ check("currentLeader single-node nodeId", single.nodeId === "single-node-local");
592
+ check("currentLeader single-node lease never expires", single.leaseExpiresAt === Infinity);
593
+ check("currentLeader single-node fencingToken 0", single.fencingToken === 0);
594
+
595
+ var d0 = await _invokeDiscovery();
596
+ check("discovery single-node replies 200", d0.status === 200);
597
+ check("discovery single-node reports the synthetic leader",
598
+ d0.body && d0.body.leader && d0.body.leader.nodeId === "single-node-local");
599
+ check("discovery emits Cache-Control: no-store",
600
+ d0.headers && d0.headers["cache-control"] === "no-store");
601
+
602
+ // Live leader through the provider.
603
+ b.cluster._resetForTest();
604
+ var s = _makeStubProvider();
605
+ s.ctl.acquireResult = "lease";
606
+ try {
607
+ await b.cluster.init({
608
+ nodeId: "disco-node", role: "leader", provider: s.provider,
609
+ endpoint: "https://disco.internal:8443",
610
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
611
+ });
612
+
613
+ s.ctl.currentLeaderResult = {
614
+ nodeId: "disco-node", leaseExpiresAt: Date.now() + C.TIME.seconds(30),
615
+ fencingToken: 7, endpoint: "https://disco.internal:8443",
616
+ };
617
+ var leader = await b.cluster.currentLeader();
618
+ check("currentLeader returns the provider snapshot", leader && leader.nodeId === "disco-node");
619
+
620
+ var dLeader = await _invokeDiscovery();
621
+ check("discovery with a live leader replies 200", dLeader.status === 200);
622
+ check("discovery echoes the leader nodeId",
623
+ dLeader.body.leader && dLeader.body.leader.nodeId === "disco-node");
624
+ check("discovery self block reflects this node",
625
+ dLeader.body.self && dLeader.body.self.nodeId === "disco-node" &&
626
+ dLeader.body.self.isLeader === true);
627
+
628
+ // No leader (election in progress / DB has no live row).
629
+ s.ctl.currentLeaderResult = null;
630
+ var dNone = await _invokeDiscovery();
631
+ check("discovery with no leader replies 503", dNone.status === 503);
632
+ check("discovery no-leader body carries a null leader", dNone.body.leader === null);
633
+
634
+ // Provider error → generic 503, no internal detail echoed.
635
+ s.ctl.currentLeaderResult = "throw";
636
+ var dErr = await _invokeDiscovery();
637
+ check("discovery on provider error replies 503", dErr.status === 503);
638
+ check("discovery error body uses a generic reason",
639
+ dErr.body.error === "leader lookup unavailable");
640
+ check("discovery error body does not echo the internal message",
641
+ !/boom/.test(JSON.stringify(dErr.body)));
642
+ } finally {
643
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
644
+ b.cluster._resetForTest();
645
+ }
646
+ }
647
+
648
+ // ---- boot-time chain-tip rollback detection ----
649
+
650
+ async function testChainTipRollback() {
651
+ // Counter regression → FATAL rollback refusal.
652
+ var fx1 = await _coordFixture();
653
+ try {
654
+ await _seed(fx1.driver,
655
+ "CREATE TABLE _blamejs_audit_tip (scope TEXT, atMonotonicCounter INTEGER, rowHash TEXT)");
656
+ await _seed(fx1.driver, "CREATE TABLE _blamejs_audit_log (monotonicCounter INTEGER, rowHash TEXT)");
657
+ await _seed(fx1.driver,
658
+ "INSERT INTO _blamejs_audit_tip (scope, atMonotonicCounter, rowHash) VALUES ('audit', 100, NULL)");
659
+ var s = _makeStubProvider();
660
+ var threw = null;
661
+ try { await _initFollowerAgainst("ops", s.provider); } catch (e) { threw = e; }
662
+ check("counter regression refuses boot", threw && threw.code === "ROLLBACK_DETECTED");
663
+ check("counter regression message names the audit chain",
664
+ threw && /audit-log rollback/.test(threw.message));
665
+ } finally {
666
+ await fx1.teardown();
667
+ }
668
+
669
+ // Row-hash substitution at the recorded tip counter → FATAL rollback.
670
+ var fx2 = await _coordFixture();
671
+ try {
672
+ await _seed(fx2.driver,
673
+ "CREATE TABLE _blamejs_audit_tip (scope TEXT, atMonotonicCounter INTEGER, rowHash TEXT)");
674
+ await _seed(fx2.driver, "CREATE TABLE _blamejs_audit_log (monotonicCounter INTEGER, rowHash TEXT)");
675
+ await _seed(fx2.driver,
676
+ "INSERT INTO _blamejs_audit_tip (scope, atMonotonicCounter, rowHash) VALUES ('audit', 5, 'HASH_A')");
677
+ await _seed(fx2.driver,
678
+ "INSERT INTO _blamejs_audit_log (monotonicCounter, rowHash) VALUES (5, 'HASH_B')");
679
+ var s2 = _makeStubProvider();
680
+ var threw2 = null;
681
+ try { await _initFollowerAgainst("ops", s2.provider); } catch (e) { threw2 = e; }
682
+ check("row-hash substitution refuses boot", threw2 && threw2.code === "ROLLBACK_DETECTED");
683
+ check("row-hash substitution message notes the mismatch",
684
+ threw2 && /row-hash mismatch/.test(threw2.message));
685
+ } finally {
686
+ await fx2.teardown();
687
+ }
688
+
689
+ // A non-missing-table query error is re-thrown, not swallowed as a skip.
690
+ var fx3 = await _coordFixture();
691
+ try {
692
+ // Tip table exists but lacks the queried columns → "no such column".
693
+ await _seed(fx3.driver, "CREATE TABLE _blamejs_audit_tip (scope TEXT)");
694
+ var s3 = _makeStubProvider();
695
+ var threw3 = null;
696
+ try { await _initFollowerAgainst("ops", s3.provider); } catch (e) { threw3 = e; }
697
+ check("a non-missing-table error propagates out of the rollback check",
698
+ threw3 && /no such column/i.test(threw3.message || ""));
699
+ } finally {
700
+ await fx3.teardown();
701
+ }
702
+
703
+ // Empty tip table → skip (first cluster boot / operator-cleared).
704
+ var fx4 = await _coordFixture();
705
+ try {
706
+ await _seed(fx4.driver,
707
+ "CREATE TABLE _blamejs_audit_tip (scope TEXT, atMonotonicCounter INTEGER, rowHash TEXT)");
708
+ await _seed(fx4.driver,
709
+ "CREATE TABLE _blamejs_consent_tip (scope TEXT, atMonotonicCounter INTEGER, rowHash TEXT)");
710
+ var s4 = _makeStubProvider();
711
+ var threw4 = null;
712
+ try { await _initFollowerAgainst("ops", s4.provider); } catch (e) { threw4 = e; }
713
+ check("an empty tip table skips the rollback check and boots", threw4 === null);
714
+ check("empty-tip boot reaches cluster mode", b.cluster.isClusterMode() === true);
715
+ } finally {
716
+ await fx4.teardown();
717
+ }
718
+
719
+ // Consistent chains → the rollback check passes for both audit and
720
+ // consent, exercising both the hash-absent and hash-present branches.
721
+ var fx5 = await _coordFixture();
722
+ try {
723
+ // audit: tip rowHash NULL, counter present in the log → hash-absent OK.
724
+ await _seed(fx5.driver,
725
+ "CREATE TABLE _blamejs_audit_tip (scope TEXT, atMonotonicCounter INTEGER, rowHash TEXT)");
726
+ await _seed(fx5.driver, "CREATE TABLE _blamejs_audit_log (monotonicCounter INTEGER, rowHash TEXT)");
727
+ await _seed(fx5.driver,
728
+ "INSERT INTO _blamejs_audit_tip (scope, atMonotonicCounter, rowHash) VALUES ('audit', 2, NULL)");
729
+ await _seed(fx5.driver,
730
+ "INSERT INTO _blamejs_audit_log (monotonicCounter, rowHash) VALUES (2, 'X')");
731
+ // consent: tip rowHash present + matching log row → hash-present OK.
732
+ await _seed(fx5.driver,
733
+ "CREATE TABLE _blamejs_consent_tip (scope TEXT, atMonotonicCounter INTEGER, rowHash TEXT)");
734
+ await _seed(fx5.driver, "CREATE TABLE _blamejs_consent_log (monotonicCounter INTEGER, rowHash TEXT)");
735
+ await _seed(fx5.driver,
736
+ "INSERT INTO _blamejs_consent_tip (scope, atMonotonicCounter, rowHash) VALUES ('consent', 3, 'HASH_C')");
737
+ await _seed(fx5.driver,
738
+ "INSERT INTO _blamejs_consent_log (monotonicCounter, rowHash) VALUES (3, 'HASH_C')");
739
+ var s5 = _makeStubProvider();
740
+ var threw5 = null;
741
+ try { await _initFollowerAgainst("ops", s5.provider); } catch (e) { threw5 = e; }
742
+ check("consistent chains pass the rollback check", threw5 === null);
743
+ check("consistent-chain boot reaches cluster mode", b.cluster.isClusterMode() === true);
744
+ } finally {
745
+ await fx5.teardown();
746
+ }
747
+ }
748
+
749
+ // ---- vault-key consistency ----
750
+
751
+ async function testVaultKeyConsistency() {
752
+ // Cross-node drift with no rotation declared → FATAL refusal.
753
+ var fx1 = await _coordFixture();
754
+ try {
755
+ await _seed(fx1.driver,
756
+ "CREATE TABLE _blamejs_cluster_state (scope TEXT PRIMARY KEY, vaultKeyFp TEXT, " +
757
+ "recordedAt INTEGER, recordedByNode TEXT)");
758
+ await _seed(fx1.driver,
759
+ "INSERT INTO _blamejs_cluster_state (scope, vaultKeyFp, recordedAt, recordedByNode) " +
760
+ "VALUES ('state', ?, ?, 'peer-node')", [_bogusFp("b"), Date.now()]);
761
+ var s = _makeStubProvider();
762
+ var threw = null;
763
+ try { await _initFollowerAgainst("ops", s.provider); } catch (e) { threw = e; }
764
+ check("undeclared vault-key drift refuses boot", threw && threw.code === "VAULT_KEY_DRIFT");
765
+ } finally {
766
+ await fx1.teardown();
767
+ }
768
+
769
+ // Rotation declared but the local key doesn't match the blessed one.
770
+ var fx2 = await _coordFixture();
771
+ try {
772
+ await _seed(fx2.driver,
773
+ "CREATE TABLE _blamejs_cluster_state (scope TEXT PRIMARY KEY, vaultKeyFp TEXT, " +
774
+ "recordedAt INTEGER, recordedByNode TEXT)");
775
+ await _seed(fx2.driver,
776
+ "INSERT INTO _blamejs_cluster_state (scope, vaultKeyFp, recordedAt, recordedByNode) " +
777
+ "VALUES ('state', ?, ?, 'peer-node')", [_bogusFp("b"), Date.now()]);
778
+ var s2 = _makeStubProvider();
779
+ var threw2 = null;
780
+ try {
781
+ await b.cluster.init({
782
+ nodeId: "rot-mismatch", role: "follower", provider: s2.provider,
783
+ externalDbBackend: "ops", dialect: "sqlite",
784
+ acceptVaultKeyRotation: true, expectedVaultKeyFp: _bogusFp("0"),
785
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
786
+ });
787
+ } catch (e) { threw2 = e; }
788
+ check("a blessed fingerprint the local key can't match refuses boot",
789
+ threw2 && threw2.code === "VAULT_KEY_ROTATION_MISMATCH");
790
+ } finally {
791
+ await fx2.teardown();
792
+ }
793
+
794
+ // Rotation adopted: the canonical row advances to the local fingerprint
795
+ // and the rotation epoch bumps. The pre-seeded row already carries a
796
+ // rotationEpoch column, exercising the swallowed "column exists" ALTER.
797
+ var fx3 = await _coordFixture();
798
+ try {
799
+ await _seed(fx3.driver,
800
+ "CREATE TABLE _blamejs_cluster_state (scope TEXT PRIMARY KEY, vaultKeyFp TEXT, " +
801
+ "recordedAt INTEGER, recordedByNode TEXT, rotationEpoch INTEGER)");
802
+ await _seed(fx3.driver,
803
+ "INSERT INTO _blamejs_cluster_state (scope, vaultKeyFp, recordedAt, recordedByNode, rotationEpoch) " +
804
+ "VALUES ('state', ?, ?, 'peer-node', 5)", [_bogusFp("c"), Date.now()]);
805
+ var s3 = _makeStubProvider();
806
+ var threw3 = null;
807
+ try {
808
+ await b.cluster.init({
809
+ nodeId: "rot-adopt", role: "follower", provider: s3.provider,
810
+ externalDbBackend: "ops", dialect: "sqlite",
811
+ acceptVaultKeyRotation: true,
812
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
813
+ });
814
+ } catch (e) { threw3 = e; }
815
+ check("a declared rotation is adopted and boots", threw3 === null);
816
+ // The canonical row now holds a real fingerprint (not the bogus seed)
817
+ // and the epoch advanced past the seeded value.
818
+ var after = await _seed(fx3.driver,
819
+ "SELECT vaultKeyFp, rotationEpoch FROM _blamejs_cluster_state WHERE scope = 'state'");
820
+ var row = after.rows && after.rows[0];
821
+ check("adoption replaces the canonical fingerprint",
822
+ row && row.vaultKeyFp !== _bogusFp("c") && row.vaultKeyFp.length === 128);
823
+ check("adoption bumps the rotation epoch", row && Number(row.rotationEpoch) === 6);
824
+ } finally {
825
+ await fx3.teardown();
826
+ }
827
+ }
828
+
829
+ // ---- vault-key consistency: fail-closed guards via lying backends ----
830
+
831
+ // A backend that accepts the cluster-state INSERT but reports no row on the
832
+ // follow-up SELECT — modelling an external DB silently dropping the write.
833
+ function _makeStateVanishesDriver() {
834
+ return {
835
+ connect: async function () { return {}; },
836
+ query: async function (_client, sqlText) {
837
+ if (/audit_tip|consent_tip/i.test(sqlText)) throw new Error("no such table: tip");
838
+ if (/^\s*INSERT\s+INTO\s+_blamejs_cluster_state/i.test(sqlText)) return { rows: [], rowCount: 1 };
839
+ if (/^\s*ALTER\s+TABLE/i.test(sqlText)) return { rows: [], rowCount: 0 };
840
+ if (/_blamejs_cluster_state/i.test(sqlText)) return { rows: [] };
841
+ return { rows: [], rowCount: 0 };
842
+ },
843
+ close: async function () {},
844
+ };
845
+ }
846
+
847
+ // A backend where the post-adoption re-read reports a fingerprint that is
848
+ // neither the old canonical nor this node's — a concurrent peer advancing
849
+ // the cluster to a third key the declared rotation does not cover.
850
+ function _makeConcurrentDriftDriver() {
851
+ var selects = 0;
852
+ return {
853
+ connect: async function () { return {}; },
854
+ query: async function (_client, sqlText) {
855
+ if (/audit_tip|consent_tip/i.test(sqlText)) throw new Error("no such table: tip");
856
+ if (/^\s*INSERT\s+INTO\s+_blamejs_cluster_state/i.test(sqlText)) return { rows: [], rowCount: 0 };
857
+ if (/^\s*ALTER\s+TABLE/i.test(sqlText)) return { rows: [], rowCount: 0 };
858
+ if (/^\s*UPDATE\s+_blamejs_cluster_state/i.test(sqlText)) return { rows: [], rowCount: 1 };
859
+ if (/_blamejs_cluster_state/i.test(sqlText)) {
860
+ selects += 1;
861
+ // 1st select = canonical read; 2nd = post-adopt re-read. Both
862
+ // report a foreign fingerprint (never this node's). The canonical
863
+ // row carries a null rotationEpoch (a legacy pre-epoch row), so the
864
+ // epoch defaults to 0 before the bump.
865
+ var fp = selects === 1 ? _bogusFp("a") : _bogusFp("d");
866
+ var epoch = selects === 1 ? null : 1;
867
+ return { rows: [{ vaultKeyFp: fp, recordedByNode: "peer", recordedAt: 1, rotationEpoch: epoch }] };
868
+ }
869
+ return { rows: [], rowCount: 0 };
870
+ },
871
+ close: async function () {},
872
+ };
873
+ }
874
+
875
+ // A backend where the tip tables are absent (skip) but the cluster-state
876
+ // upsert fails for a reason that is NOT a missing relation — the fault must
877
+ // propagate, not be mistaken for a gates-only skip.
878
+ function _makeStateUpsertErrorDriver() {
879
+ return {
880
+ connect: async function () { return {}; },
881
+ query: async function (_client, sqlText) {
882
+ if (/audit_tip|consent_tip/i.test(sqlText)) throw new Error("no such table: tip");
883
+ if (/^\s*INSERT\s+INTO\s+_blamejs_cluster_state/i.test(sqlText)) {
884
+ throw new Error("disk I/O error while writing cluster state");
885
+ }
886
+ return { rows: [], rowCount: 0 };
887
+ },
888
+ close: async function () {},
889
+ };
890
+ }
891
+
892
+ // A backend surfacing structured missing-relation faults (MySQL errno 1146
893
+ // on the tip tables, Postgres SQLSTATE 42P01 on the state table) so the
894
+ // classifier's code/errno branch is exercised, not just its message regex.
895
+ function _makeStructuredMissingRelationDriver() {
896
+ return {
897
+ connect: async function () { return {}; },
898
+ query: async function (_client, sqlText) {
899
+ if (/audit_tip|consent_tip/i.test(sqlText)) {
900
+ var e = new Error("Table 'db.tip' doesn't exist");
901
+ e.errno = 1146; e.code = "ER_NO_SUCH_TABLE"; e.sqlState = "42S02";
902
+ throw e;
903
+ }
904
+ var e2 = new Error("relation missing");
905
+ e2.code = "42P01";
906
+ throw e2;
907
+ },
908
+ close: async function () {},
909
+ };
910
+ }
911
+
912
+ async function _runWithCustomBackend(backends, provider, initOpts) {
913
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cluster-drv-"));
914
+ b.cluster._resetForTest();
915
+ await setupTestDb(tmpDir);
916
+ b.externalDb.init({ backends: backends });
917
+ var threw = null;
918
+ try { await b.cluster.init(initOpts); } catch (e) { threw = e; }
919
+ return {
920
+ threw: threw,
921
+ teardown: async function () {
922
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
923
+ try { await b.externalDb.shutdown(); } catch (_e) { /* best-effort */ }
924
+ await teardownTestDb(tmpDir);
925
+ },
926
+ };
927
+ }
928
+
929
+ async function testVaultKeyFailClosedGuards() {
930
+ var baseOpts = {
931
+ role: "follower", externalDbBackend: "x", dialect: "sqlite",
932
+ leaseTtl: C.TIME.seconds(30), heartbeatInterval: C.TIME.seconds(15),
933
+ };
934
+
935
+ // External DB not honoring the state write → fail closed.
936
+ var d1 = _makeStateVanishesDriver();
937
+ var r1 = await _runWithCustomBackend(
938
+ { x: { connect: d1.connect, query: d1.query, close: d1.close } },
939
+ _makeStubProvider().provider,
940
+ Object.assign({ nodeId: "state-vanish", provider: _makeStubProvider().provider }, baseOpts));
941
+ try {
942
+ check("a vanished cluster-state row refuses boot",
943
+ r1.threw && r1.threw.code === "CLUSTER_STATE_MISSING");
944
+ } finally { await r1.teardown(); }
945
+
946
+ // Concurrent peer advanced to a third key after we adopted → fail closed.
947
+ var d2 = _makeConcurrentDriftDriver();
948
+ var r2 = await _runWithCustomBackend(
949
+ { x: { connect: d2.connect, query: d2.query, close: d2.close } },
950
+ _makeStubProvider().provider,
951
+ Object.assign({ nodeId: "concurrent-drift", provider: _makeStubProvider().provider,
952
+ acceptVaultKeyRotation: true }, baseOpts));
953
+ try {
954
+ check("a concurrent divergent adoption refuses boot",
955
+ r2.threw && r2.threw.code === "VAULT_KEY_DRIFT" &&
956
+ /after rotation-accept/.test(r2.threw.message));
957
+ } finally { await r2.teardown(); }
958
+
959
+ // A non-missing-relation state-upsert fault propagates (not skipped).
960
+ var dErr = _makeStateUpsertErrorDriver();
961
+ var rErr = await _runWithCustomBackend(
962
+ { x: { connect: dErr.connect, query: dErr.query, close: dErr.close } },
963
+ _makeStubProvider().provider,
964
+ Object.assign({ nodeId: "state-upsert-error", provider: _makeStubProvider().provider }, baseOpts));
965
+ try {
966
+ check("a non-missing-relation state-upsert fault propagates",
967
+ rErr.threw && /disk I\/O error/.test(rErr.threw.message || ""));
968
+ } finally { await rErr.teardown(); }
969
+
970
+ // Structured missing-relation codes classify as skip (not re-thrown).
971
+ var d3 = _makeStructuredMissingRelationDriver();
972
+ var r3 = await _runWithCustomBackend(
973
+ { x: { connect: d3.connect, query: d3.query, close: d3.close } },
974
+ _makeStubProvider().provider,
975
+ Object.assign({ nodeId: "structured-missing", provider: _makeStubProvider().provider }, baseOpts));
976
+ try {
977
+ check("structured missing-relation faults skip the checks and boot", r3.threw === null);
978
+ check("structured-missing boot reaches cluster mode", b.cluster.isClusterMode() === true);
979
+ } finally { await r3.teardown(); }
980
+ }
981
+
982
+ // ---- vault not initialized → gates-only skip ----
983
+
984
+ async function testVaultNotInitializedGatesOnly() {
985
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cluster-noVault-"));
986
+ b.cluster._resetForTest();
987
+ // Deliberately do NOT init the vault: a gates-only cluster (leader
988
+ // election wired, framework sealed-column state still local) must skip
989
+ // the vault-key consistency check rather than fail boot.
990
+ b.vault._resetForTest();
991
+
992
+ var dbPath = path.join(tmpDir, "ha-coord.db");
993
+ var driver = _makeSqliteDriver(dbPath);
994
+ b.externalDb.init({
995
+ backends: { ops: { connect: driver.connect, query: driver.query, close: driver.close } },
996
+ });
997
+ var s = _makeStubProvider();
998
+ try {
999
+ var threw = null;
1000
+ try { await _initFollowerAgainst("ops", s.provider); } catch (e) { threw = e; }
1001
+ check("gates-only cluster boots without an initialized vault", threw === null);
1002
+ check("gates-only cluster reaches cluster mode", b.cluster.isClusterMode() === true);
1003
+ } finally {
1004
+ try { await b.cluster.shutdown(); } catch (_e) { /* idempotent */ }
1005
+ try { await b.externalDb.shutdown(); } catch (_e) { /* best-effort */ }
1006
+ try { driver._close(); } catch (_e) { /* best-effort */ }
1007
+ b.cluster._resetForTest();
1008
+ b.vault._resetForTest();
1009
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch (_e) { /* best-effort */ }
1010
+ }
1011
+ }
1012
+
1013
+ async function run() {
1014
+ await testExternalDbBackendAndOnTransition();
1015
+ await testInitConfigValidation();
1016
+ await testSyncSurfaceAndGetters();
1017
+ await testHeartbeatStateMachine();
1018
+ await testCurrentLeaderAndDiscovery();
1019
+ await testChainTipRollback();
1020
+ await testVaultKeyConsistency();
1021
+ await testVaultKeyFailClosedGuards();
1022
+ await testVaultNotInitializedGatesOnly();
1023
+ }
1024
+
1025
+ module.exports = { run: run };
1026
+
1027
+ if (require.main === module) {
1028
+ run().then(
1029
+ function () { console.log("[cluster] OK — " + helpers.getChecks() + " checks passed"); },
1030
+ function (e) { console.error("FAIL:", e); process.exit(1); }
1031
+ );
1032
+ }