@blamejs/blamejs-shop 0.0.44

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 (1220) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +17 -0
  3. package/README.md +117 -0
  4. package/SECURITY.md +139 -0
  5. package/lib/admin.js +952 -0
  6. package/lib/analytics.js +267 -0
  7. package/lib/cart.js +279 -0
  8. package/lib/catalog-import.js +344 -0
  9. package/lib/catalog.js +769 -0
  10. package/lib/checkout.js +320 -0
  11. package/lib/config.js +151 -0
  12. package/lib/customers.js +322 -0
  13. package/lib/email.js +242 -0
  14. package/lib/externaldb-d1.js +283 -0
  15. package/lib/index.js +57 -0
  16. package/lib/inventory-alerts.js +198 -0
  17. package/lib/newsletter.js +142 -0
  18. package/lib/order.js +380 -0
  19. package/lib/payment.js +318 -0
  20. package/lib/pricing.js +185 -0
  21. package/lib/r2-bridge.js +169 -0
  22. package/lib/shipping.js +185 -0
  23. package/lib/storefront.js +2160 -0
  24. package/lib/subscriptions.js +410 -0
  25. package/lib/tax.js +161 -0
  26. package/lib/theme.js +194 -0
  27. package/lib/vendor/MANIFEST.json +19 -0
  28. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +23 -0
  29. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +34 -0
  30. package/lib/vendor/blamejs/.clusterfuzzlite/project.yaml +16 -0
  31. package/lib/vendor/blamejs/.dockerignore +45 -0
  32. package/lib/vendor/blamejs/.gitattributes +42 -0
  33. package/lib/vendor/blamejs/.github/CODEOWNERS +4 -0
  34. package/lib/vendor/blamejs/.github/FUNDING.yml +2 -0
  35. package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/bug_report.md +58 -0
  36. package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/config.yml +8 -0
  37. package/lib/vendor/blamejs/.github/ISSUE_TEMPLATE/feature_request.md +99 -0
  38. package/lib/vendor/blamejs/.github/PULL_REQUEST_TEMPLATE.md +77 -0
  39. package/lib/vendor/blamejs/.github/dependabot.yml +37 -0
  40. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +148 -0
  41. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +107 -0
  42. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +122 -0
  43. package/lib/vendor/blamejs/.github/workflows/ci.yml +511 -0
  44. package/lib/vendor/blamejs/.github/workflows/codeql.yml +50 -0
  45. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +655 -0
  46. package/lib/vendor/blamejs/.github/workflows/release-container.yml +406 -0
  47. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +101 -0
  48. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +134 -0
  49. package/lib/vendor/blamejs/.gitignore +102 -0
  50. package/lib/vendor/blamejs/.gitleaks.toml +166 -0
  51. package/lib/vendor/blamejs/.hadolint.yaml +18 -0
  52. package/lib/vendor/blamejs/.npmrc +5 -0
  53. package/lib/vendor/blamejs/.pinact.yaml +17 -0
  54. package/lib/vendor/blamejs/ARCHITECTURE.md +158 -0
  55. package/lib/vendor/blamejs/CHANGELOG.md +1351 -0
  56. package/lib/vendor/blamejs/CODE_OF_CONDUCT.md +86 -0
  57. package/lib/vendor/blamejs/CONTRIBUTING.md +156 -0
  58. package/lib/vendor/blamejs/GOVERNANCE.md +201 -0
  59. package/lib/vendor/blamejs/LICENSE +201 -0
  60. package/lib/vendor/blamejs/LTS-CALENDAR.md +29 -0
  61. package/lib/vendor/blamejs/MIGRATING.md +29 -0
  62. package/lib/vendor/blamejs/NOTICE +81 -0
  63. package/lib/vendor/blamejs/README.md +304 -0
  64. package/lib/vendor/blamejs/SECURITY.md +432 -0
  65. package/lib/vendor/blamejs/api-snapshot.json +48709 -0
  66. package/lib/vendor/blamejs/assets/BlameJS_Logo.png +0 -0
  67. package/lib/vendor/blamejs/assets/BlameJS_Logo.svg +129 -0
  68. package/lib/vendor/blamejs/bench/README.md +77 -0
  69. package/lib/vendor/blamejs/bench/_helpers.js +70 -0
  70. package/lib/vendor/blamejs/bench/baseline.json +183 -0
  71. package/lib/vendor/blamejs/bench/crypto-hash.bench.js +19 -0
  72. package/lib/vendor/blamejs/bench/crypto-symmetric.bench.js +28 -0
  73. package/lib/vendor/blamejs/bench/run.js +140 -0
  74. package/lib/vendor/blamejs/bench/safe-json.bench.js +31 -0
  75. package/lib/vendor/blamejs/bin/blamejs.js +13 -0
  76. package/lib/vendor/blamejs/docker/caddy/Caddyfile +46 -0
  77. package/lib/vendor/blamejs/docker/coredns/Corefile +37 -0
  78. package/lib/vendor/blamejs/docker/haproxy/haproxy.cfg +52 -0
  79. package/lib/vendor/blamejs/docker/init/generate-certs.sh +118 -0
  80. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +87 -0
  81. package/lib/vendor/blamejs/docker/mitmproxy/config.yaml +16 -0
  82. package/lib/vendor/blamejs/docker/mongo/init-tls.sh +17 -0
  83. package/lib/vendor/blamejs/docker/mysql/my.cnf +12 -0
  84. package/lib/vendor/blamejs/docker/nats/nats.conf +33 -0
  85. package/lib/vendor/blamejs/docker/postgres/init-tls.sh +17 -0
  86. package/lib/vendor/blamejs/docker/postgres/postgresql.conf +18 -0
  87. package/lib/vendor/blamejs/docker/rabbitmq/rabbitmq.conf +18 -0
  88. package/lib/vendor/blamejs/docker/redis/redis.conf +15 -0
  89. package/lib/vendor/blamejs/docker/squid/squid.conf +24 -0
  90. package/lib/vendor/blamejs/docker/syslog/syslog-ng.conf +34 -0
  91. package/lib/vendor/blamejs/docker-compose.test.yml +545 -0
  92. package/lib/vendor/blamejs/docs/cis-postgres-crosswalk.md +102 -0
  93. package/lib/vendor/blamejs/docs/cis-sqlite-equivalent.md +92 -0
  94. package/lib/vendor/blamejs/eslint.config.mjs +204 -0
  95. package/lib/vendor/blamejs/examples/wiki/Caddyfile +40 -0
  96. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +218 -0
  97. package/lib/vendor/blamejs/examples/wiki/Dockerfile +120 -0
  98. package/lib/vendor/blamejs/examples/wiki/README.md +157 -0
  99. package/lib/vendor/blamejs/examples/wiki/cli-snapshot.json +250 -0
  100. package/lib/vendor/blamejs/examples/wiki/docker-compose.prod.yml +231 -0
  101. package/lib/vendor/blamejs/examples/wiki/docker-compose.yml +166 -0
  102. package/lib/vendor/blamejs/examples/wiki/env-snapshot.json +217 -0
  103. package/lib/vendor/blamejs/examples/wiki/lib/auto-site-entries.js +139 -0
  104. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +555 -0
  105. package/lib/vendor/blamejs/examples/wiki/lib/harvest-cli.js +507 -0
  106. package/lib/vendor/blamejs/examples/wiki/lib/harvest-env-vars.js +435 -0
  107. package/lib/vendor/blamejs/examples/wiki/lib/harvest-errors.js +282 -0
  108. package/lib/vendor/blamejs/examples/wiki/lib/harvest-vendored-deps.js +321 -0
  109. package/lib/vendor/blamejs/examples/wiki/lib/nav.js +15 -0
  110. package/lib/vendor/blamejs/examples/wiki/lib/opts-resolver.js +75 -0
  111. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +508 -0
  112. package/lib/vendor/blamejs/examples/wiki/lib/section.js +276 -0
  113. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +587 -0
  114. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +318 -0
  115. package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +122 -0
  116. package/lib/vendor/blamejs/examples/wiki/migrations/0001-pages-schema.js +74 -0
  117. package/lib/vendor/blamejs/examples/wiki/package.json +18 -0
  118. package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.png +0 -0
  119. package/lib/vendor/blamejs/examples/wiki/public/img/blamejs-logo.svg +129 -0
  120. package/lib/vendor/blamejs/examples/wiki/public/robots.txt +5 -0
  121. package/lib/vendor/blamejs/examples/wiki/public/vendor/MANIFEST.json +30 -0
  122. package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.css +1 -0
  123. package/lib/vendor/blamejs/examples/wiki/public/vendor/prism.js +15 -0
  124. package/lib/vendor/blamejs/examples/wiki/public/wiki.css +1250 -0
  125. package/lib/vendor/blamejs/examples/wiki/routes/admin.js +366 -0
  126. package/lib/vendor/blamejs/examples/wiki/routes/integration.js +230 -0
  127. package/lib/vendor/blamejs/examples/wiki/routes/pages.js +266 -0
  128. package/lib/vendor/blamejs/examples/wiki/scripts/backfill-module-metadata.js +214 -0
  129. package/lib/vendor/blamejs/examples/wiki/seeders/prod/0001-default-pages.js +35 -0
  130. package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/_index.js +34 -0
  131. package/lib/vendor/blamejs/examples/wiki/seeders/prod/pages/api.js +76 -0
  132. package/lib/vendor/blamejs/examples/wiki/server.js +129 -0
  133. package/lib/vendor/blamejs/examples/wiki/site.config.js +197 -0
  134. package/lib/vendor/blamejs/examples/wiki/snippets/README.md +38 -0
  135. package/lib/vendor/blamejs/examples/wiki/snippets/auth/password-hash.example.js +15 -0
  136. package/lib/vendor/blamejs/examples/wiki/src/editor.js +103 -0
  137. package/lib/vendor/blamejs/examples/wiki/src/wiki.js +349 -0
  138. package/lib/vendor/blamejs/examples/wiki/test/AUDIT.md +155 -0
  139. package/lib/vendor/blamejs/examples/wiki/test/codebase-patterns.test.js +594 -0
  140. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +741 -0
  141. package/lib/vendor/blamejs/examples/wiki/test/find-missing-pages.js +254 -0
  142. package/lib/vendor/blamejs/examples/wiki/test/integration.js +391 -0
  143. package/lib/vendor/blamejs/examples/wiki/test/validate-cli-snapshot.js +379 -0
  144. package/lib/vendor/blamejs/examples/wiki/test/validate-env-snapshot.js +346 -0
  145. package/lib/vendor/blamejs/examples/wiki/test/validate-nav-coverage.js +212 -0
  146. package/lib/vendor/blamejs/examples/wiki/test/validate-site-coverage.js +252 -0
  147. package/lib/vendor/blamejs/examples/wiki/test/validate-source-comment-blocks.js +107 -0
  148. package/lib/vendor/blamejs/examples/wiki/views/_layout.html +115 -0
  149. package/lib/vendor/blamejs/examples/wiki/views/admin/api-keys.html +51 -0
  150. package/lib/vendor/blamejs/examples/wiki/views/admin/dashboard.html +22 -0
  151. package/lib/vendor/blamejs/examples/wiki/views/admin/edit.html +17 -0
  152. package/lib/vendor/blamejs/examples/wiki/views/home.html +85 -0
  153. package/lib/vendor/blamejs/examples/wiki/views/login.html +18 -0
  154. package/lib/vendor/blamejs/examples/wiki/views/page.html +5 -0
  155. package/lib/vendor/blamejs/examples/wiki/views/partials/nav.html +13 -0
  156. package/lib/vendor/blamejs/examples/wiki/views/search.html +19 -0
  157. package/lib/vendor/blamejs/examples/wiki/wiki.config.js +15 -0
  158. package/lib/vendor/blamejs/fuzz/README.md +137 -0
  159. package/lib/vendor/blamejs/fuzz/_expected.js +35 -0
  160. package/lib/vendor/blamejs/fuzz/guard-agent-registry.fuzz.js +22 -0
  161. package/lib/vendor/blamejs/fuzz/guard-csv.fuzz.js +16 -0
  162. package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/01-basic.csv +3 -0
  163. package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/02-formula.csv +1 -0
  164. package/lib/vendor/blamejs/fuzz/guard-csv_seed_corpus/03-hyperlink.csv +1 -0
  165. package/lib/vendor/blamejs/fuzz/guard-dsn.fuzz.js +22 -0
  166. package/lib/vendor/blamejs/fuzz/guard-email.fuzz.js +16 -0
  167. package/lib/vendor/blamejs/fuzz/guard-email_seed_corpus/01-basic.eml +5 -0
  168. package/lib/vendor/blamejs/fuzz/guard-envelope.fuzz.js +24 -0
  169. package/lib/vendor/blamejs/fuzz/guard-event-bus-payload.fuzz.js +24 -0
  170. package/lib/vendor/blamejs/fuzz/guard-event-bus-topic.fuzz.js +20 -0
  171. package/lib/vendor/blamejs/fuzz/guard-html.fuzz.js +16 -0
  172. package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/01-basic.html +1 -0
  173. package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/02-script.html +1 -0
  174. package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/03-event.html +1 -0
  175. package/lib/vendor/blamejs/fuzz/guard-html_seed_corpus/04-jsurl.html +1 -0
  176. package/lib/vendor/blamejs/fuzz/guard-idempotency-key.fuzz.js +20 -0
  177. package/lib/vendor/blamejs/fuzz/guard-imap-command.fuzz.js +35 -0
  178. package/lib/vendor/blamejs/fuzz/guard-jmap.fuzz.js +41 -0
  179. package/lib/vendor/blamejs/fuzz/guard-json.fuzz.js +16 -0
  180. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/01-basic.json +1 -0
  181. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/02-proto.json +1 -0
  182. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/03-dupkey.json +1 -0
  183. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/04-nan.json +1 -0
  184. package/lib/vendor/blamejs/fuzz/guard-json_seed_corpus/05-bom.json +1 -0
  185. package/lib/vendor/blamejs/fuzz/guard-list-id.fuzz.js +21 -0
  186. package/lib/vendor/blamejs/fuzz/guard-list-unsubscribe.fuzz.js +25 -0
  187. package/lib/vendor/blamejs/fuzz/guard-mail-compose.fuzz.js +22 -0
  188. package/lib/vendor/blamejs/fuzz/guard-mail-move.fuzz.js +22 -0
  189. package/lib/vendor/blamejs/fuzz/guard-mail-query.fuzz.js +27 -0
  190. package/lib/vendor/blamejs/fuzz/guard-mail-reply.fuzz.js +23 -0
  191. package/lib/vendor/blamejs/fuzz/guard-mail-sieve.fuzz.js +36 -0
  192. package/lib/vendor/blamejs/fuzz/guard-managesieve-command.fuzz.js +26 -0
  193. package/lib/vendor/blamejs/fuzz/guard-markdown.fuzz.js +16 -0
  194. package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/01-basic.md +2 -0
  195. package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/02-jsurl.md +1 -0
  196. package/lib/vendor/blamejs/fuzz/guard-markdown_seed_corpus/03-jsimg.md +1 -0
  197. package/lib/vendor/blamejs/fuzz/guard-message-id.fuzz.js +26 -0
  198. package/lib/vendor/blamejs/fuzz/guard-pop3-command.fuzz.js +23 -0
  199. package/lib/vendor/blamejs/fuzz/guard-posture-chain.fuzz.js +22 -0
  200. package/lib/vendor/blamejs/fuzz/guard-saga-config.fuzz.js +32 -0
  201. package/lib/vendor/blamejs/fuzz/guard-smtp-command.fuzz.js +27 -0
  202. package/lib/vendor/blamejs/fuzz/guard-snapshot-envelope.fuzz.js +22 -0
  203. package/lib/vendor/blamejs/fuzz/guard-stream-args.fuzz.js +22 -0
  204. package/lib/vendor/blamejs/fuzz/guard-svg.fuzz.js +16 -0
  205. package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/01-basic.svg +1 -0
  206. package/lib/vendor/blamejs/fuzz/guard-svg_seed_corpus/02-script.svg +1 -0
  207. package/lib/vendor/blamejs/fuzz/guard-tenant-id.fuzz.js +20 -0
  208. package/lib/vendor/blamejs/fuzz/guard-trace-context.fuzz.js +30 -0
  209. package/lib/vendor/blamejs/fuzz/guard-xml.fuzz.js +16 -0
  210. package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/01-basic.xml +1 -0
  211. package/lib/vendor/blamejs/fuzz/guard-xml_seed_corpus/02-xxe.xml +1 -0
  212. package/lib/vendor/blamejs/fuzz/guard-yaml.fuzz.js +16 -0
  213. package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/01-basic.yaml +2 -0
  214. package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/02-anchor.yaml +2 -0
  215. package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/03-norway.yaml +1 -0
  216. package/lib/vendor/blamejs/fuzz/guard-yaml_seed_corpus/04-multidoc.yaml +4 -0
  217. package/lib/vendor/blamejs/fuzz/parsers__safe-ini.fuzz.js +16 -0
  218. package/lib/vendor/blamejs/fuzz/parsers__safe-ini_seed_corpus/01-basic.ini +2 -0
  219. package/lib/vendor/blamejs/fuzz/parsers__safe-toml.fuzz.js +16 -0
  220. package/lib/vendor/blamejs/fuzz/parsers__safe-toml_seed_corpus/01-basic.toml +4 -0
  221. package/lib/vendor/blamejs/fuzz/parsers__safe-xml.fuzz.js +16 -0
  222. package/lib/vendor/blamejs/fuzz/parsers__safe-xml_seed_corpus/01-basic.xml +1 -0
  223. package/lib/vendor/blamejs/fuzz/parsers__safe-yaml.fuzz.js +16 -0
  224. package/lib/vendor/blamejs/fuzz/parsers__safe-yaml_seed_corpus/01-basic.yaml +4 -0
  225. package/lib/vendor/blamejs/fuzz/safe-decompress.fuzz.js +49 -0
  226. package/lib/vendor/blamejs/fuzz/safe-dns.fuzz.js +29 -0
  227. package/lib/vendor/blamejs/fuzz/safe-ical.fuzz.js +16 -0
  228. package/lib/vendor/blamejs/fuzz/safe-icap.fuzz.js +42 -0
  229. package/lib/vendor/blamejs/fuzz/safe-json.fuzz.js +25 -0
  230. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/01-object.txt +1 -0
  231. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/02-array.txt +1 -0
  232. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/03-string.txt +1 -0
  233. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/04-proto.txt +1 -0
  234. package/lib/vendor/blamejs/fuzz/safe-json_seed_corpus/05-deep.txt +1 -0
  235. package/lib/vendor/blamejs/fuzz/safe-jsonpath.fuzz.js +16 -0
  236. package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/01-basic.txt +1 -0
  237. package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/02-filter.txt +1 -0
  238. package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/03-deepscan.txt +1 -0
  239. package/lib/vendor/blamejs/fuzz/safe-jsonpath_seed_corpus/04-slice.txt +1 -0
  240. package/lib/vendor/blamejs/fuzz/safe-mime.fuzz.js +27 -0
  241. package/lib/vendor/blamejs/fuzz/safe-mount-info.fuzz.js +33 -0
  242. package/lib/vendor/blamejs/fuzz/safe-sieve.fuzz.js +28 -0
  243. package/lib/vendor/blamejs/fuzz/safe-smtp.fuzz.js +64 -0
  244. package/lib/vendor/blamejs/fuzz/safe-url.fuzz.js +16 -0
  245. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/01-basic.txt +1 -0
  246. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/02-userinfo.txt +1 -0
  247. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/03-dangerous.txt +1 -0
  248. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/04-data.txt +1 -0
  249. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/05-ipv6.txt +1 -0
  250. package/lib/vendor/blamejs/fuzz/safe-url_seed_corpus/06-idn.txt +1 -0
  251. package/lib/vendor/blamejs/fuzz/safe-vcard.fuzz.js +16 -0
  252. package/lib/vendor/blamejs/index.js +678 -0
  253. package/lib/vendor/blamejs/keys/release-pqc-pub.json +7 -0
  254. package/lib/vendor/blamejs/lib/_test/crypto-fixtures.js +67 -0
  255. package/lib/vendor/blamejs/lib/a2a-tasks.js +598 -0
  256. package/lib/vendor/blamejs/lib/a2a.js +407 -0
  257. package/lib/vendor/blamejs/lib/acme.js +1448 -0
  258. package/lib/vendor/blamejs/lib/agent-audit.js +45 -0
  259. package/lib/vendor/blamejs/lib/agent-event-bus.js +382 -0
  260. package/lib/vendor/blamejs/lib/agent-idempotency.js +497 -0
  261. package/lib/vendor/blamejs/lib/agent-orchestrator.js +717 -0
  262. package/lib/vendor/blamejs/lib/agent-posture-chain.js +366 -0
  263. package/lib/vendor/blamejs/lib/agent-saga.js +321 -0
  264. package/lib/vendor/blamejs/lib/agent-snapshot.js +676 -0
  265. package/lib/vendor/blamejs/lib/agent-stream.js +269 -0
  266. package/lib/vendor/blamejs/lib/agent-tenant.js +632 -0
  267. package/lib/vendor/blamejs/lib/agent-trace.js +281 -0
  268. package/lib/vendor/blamejs/lib/ai-adverse-decision.js +184 -0
  269. package/lib/vendor/blamejs/lib/ai-content-detect.js +268 -0
  270. package/lib/vendor/blamejs/lib/ai-input.js +201 -0
  271. package/lib/vendor/blamejs/lib/ai-model-manifest.js +363 -0
  272. package/lib/vendor/blamejs/lib/ai-pref.js +340 -0
  273. package/lib/vendor/blamejs/lib/api-key.js +721 -0
  274. package/lib/vendor/blamejs/lib/api-snapshot.js +458 -0
  275. package/lib/vendor/blamejs/lib/app-shutdown.js +557 -0
  276. package/lib/vendor/blamejs/lib/app.js +365 -0
  277. package/lib/vendor/blamejs/lib/archive.js +547 -0
  278. package/lib/vendor/blamejs/lib/arg-parser.js +697 -0
  279. package/lib/vendor/blamejs/lib/argon2-builtin.js +173 -0
  280. package/lib/vendor/blamejs/lib/asn1-der.js +424 -0
  281. package/lib/vendor/blamejs/lib/asyncapi-bindings.js +160 -0
  282. package/lib/vendor/blamejs/lib/asyncapi-traits.js +143 -0
  283. package/lib/vendor/blamejs/lib/asyncapi.js +575 -0
  284. package/lib/vendor/blamejs/lib/atomic-file.js +1023 -0
  285. package/lib/vendor/blamejs/lib/audit-chain.js +266 -0
  286. package/lib/vendor/blamejs/lib/audit-daily-review.js +389 -0
  287. package/lib/vendor/blamejs/lib/audit-sign.js +751 -0
  288. package/lib/vendor/blamejs/lib/audit-tools.js +1113 -0
  289. package/lib/vendor/blamejs/lib/audit.js +1671 -0
  290. package/lib/vendor/blamejs/lib/auth/aal.js +169 -0
  291. package/lib/vendor/blamejs/lib/auth/access-lock.js +220 -0
  292. package/lib/vendor/blamejs/lib/auth/acr-vocabulary.js +265 -0
  293. package/lib/vendor/blamejs/lib/auth/ato-kill-switch.js +112 -0
  294. package/lib/vendor/blamejs/lib/auth/auth-time-tracker.js +111 -0
  295. package/lib/vendor/blamejs/lib/auth/bot-challenge.js +573 -0
  296. package/lib/vendor/blamejs/lib/auth/ciba.js +637 -0
  297. package/lib/vendor/blamejs/lib/auth/dpop.js +516 -0
  298. package/lib/vendor/blamejs/lib/auth/elevation-grant.js +306 -0
  299. package/lib/vendor/blamejs/lib/auth/fal.js +229 -0
  300. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +681 -0
  301. package/lib/vendor/blamejs/lib/auth/jwt-external.js +519 -0
  302. package/lib/vendor/blamejs/lib/auth/jwt.js +430 -0
  303. package/lib/vendor/blamejs/lib/auth/lockout.js +449 -0
  304. package/lib/vendor/blamejs/lib/auth/oauth.js +2141 -0
  305. package/lib/vendor/blamejs/lib/auth/oid4vci.js +657 -0
  306. package/lib/vendor/blamejs/lib/auth/oid4vp.js +531 -0
  307. package/lib/vendor/blamejs/lib/auth/openid-federation.js +600 -0
  308. package/lib/vendor/blamejs/lib/auth/passkey.js +676 -0
  309. package/lib/vendor/blamejs/lib/auth/password.js +693 -0
  310. package/lib/vendor/blamejs/lib/auth/saml.js +2109 -0
  311. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-disclosure.js +95 -0
  312. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +225 -0
  313. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +197 -0
  314. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +728 -0
  315. package/lib/vendor/blamejs/lib/auth/status-list.js +272 -0
  316. package/lib/vendor/blamejs/lib/auth/step-up-policy.js +335 -0
  317. package/lib/vendor/blamejs/lib/auth/step-up.js +454 -0
  318. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +505 -0
  319. package/lib/vendor/blamejs/lib/auth-header.js +148 -0
  320. package/lib/vendor/blamejs/lib/backup/bundle.js +265 -0
  321. package/lib/vendor/blamejs/lib/backup/crypto.js +176 -0
  322. package/lib/vendor/blamejs/lib/backup/index.js +1001 -0
  323. package/lib/vendor/blamejs/lib/backup/manifest.js +443 -0
  324. package/lib/vendor/blamejs/lib/boot-gates.js +174 -0
  325. package/lib/vendor/blamejs/lib/breach-deadline.js +272 -0
  326. package/lib/vendor/blamejs/lib/break-glass.js +1753 -0
  327. package/lib/vendor/blamejs/lib/budr.js +205 -0
  328. package/lib/vendor/blamejs/lib/bundler.js +461 -0
  329. package/lib/vendor/blamejs/lib/cache-redis.js +256 -0
  330. package/lib/vendor/blamejs/lib/cache-status.js +288 -0
  331. package/lib/vendor/blamejs/lib/cache.js +1331 -0
  332. package/lib/vendor/blamejs/lib/calendar.js +1240 -0
  333. package/lib/vendor/blamejs/lib/canonical-json.js +143 -0
  334. package/lib/vendor/blamejs/lib/cdn-cache-control.js +473 -0
  335. package/lib/vendor/blamejs/lib/cert.js +763 -0
  336. package/lib/vendor/blamejs/lib/chain-writer.js +259 -0
  337. package/lib/vendor/blamejs/lib/circuit-breaker.js +101 -0
  338. package/lib/vendor/blamejs/lib/cli-helpers.js +237 -0
  339. package/lib/vendor/blamejs/lib/cli.js +2328 -0
  340. package/lib/vendor/blamejs/lib/client-hints.js +318 -0
  341. package/lib/vendor/blamejs/lib/cloud-events.js +277 -0
  342. package/lib/vendor/blamejs/lib/cluster-provider-db.js +317 -0
  343. package/lib/vendor/blamejs/lib/cluster-storage.js +351 -0
  344. package/lib/vendor/blamejs/lib/cluster.js +1017 -0
  345. package/lib/vendor/blamejs/lib/cms-codec.js +826 -0
  346. package/lib/vendor/blamejs/lib/codepoint-class.js +262 -0
  347. package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +190 -0
  348. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +205 -0
  349. package/lib/vendor/blamejs/lib/compliance-ai-act-risk.js +189 -0
  350. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +200 -0
  351. package/lib/vendor/blamejs/lib/compliance-ai-act.js +821 -0
  352. package/lib/vendor/blamejs/lib/compliance-eaa.js +204 -0
  353. package/lib/vendor/blamejs/lib/compliance-sanctions-aliases.js +167 -0
  354. package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +206 -0
  355. package/lib/vendor/blamejs/lib/compliance-sanctions-fuzzy.js +297 -0
  356. package/lib/vendor/blamejs/lib/compliance-sanctions.js +569 -0
  357. package/lib/vendor/blamejs/lib/compliance.js +1558 -0
  358. package/lib/vendor/blamejs/lib/config-drift.js +426 -0
  359. package/lib/vendor/blamejs/lib/config.js +446 -0
  360. package/lib/vendor/blamejs/lib/consent.js +369 -0
  361. package/lib/vendor/blamejs/lib/constants.js +209 -0
  362. package/lib/vendor/blamejs/lib/content-credentials.js +704 -0
  363. package/lib/vendor/blamejs/lib/cookies.js +560 -0
  364. package/lib/vendor/blamejs/lib/cra-report.js +299 -0
  365. package/lib/vendor/blamejs/lib/credential-hash.js +394 -0
  366. package/lib/vendor/blamejs/lib/crypto-field.js +1017 -0
  367. package/lib/vendor/blamejs/lib/crypto-hpke-pq.js +187 -0
  368. package/lib/vendor/blamejs/lib/crypto-hpke.js +256 -0
  369. package/lib/vendor/blamejs/lib/crypto.js +1908 -0
  370. package/lib/vendor/blamejs/lib/csp.js +271 -0
  371. package/lib/vendor/blamejs/lib/csv.js +418 -0
  372. package/lib/vendor/blamejs/lib/daemon.js +481 -0
  373. package/lib/vendor/blamejs/lib/dark-patterns.js +488 -0
  374. package/lib/vendor/blamejs/lib/data-act.js +328 -0
  375. package/lib/vendor/blamejs/lib/db-collection.js +587 -0
  376. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +267 -0
  377. package/lib/vendor/blamejs/lib/db-declare-view.js +420 -0
  378. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +333 -0
  379. package/lib/vendor/blamejs/lib/db-query.js +802 -0
  380. package/lib/vendor/blamejs/lib/db-role-context.js +50 -0
  381. package/lib/vendor/blamejs/lib/db-schema.js +322 -0
  382. package/lib/vendor/blamejs/lib/db.js +3111 -0
  383. package/lib/vendor/blamejs/lib/dbsc.js +299 -0
  384. package/lib/vendor/blamejs/lib/ddl-change-control.js +523 -0
  385. package/lib/vendor/blamejs/lib/deprecate.js +377 -0
  386. package/lib/vendor/blamejs/lib/dev.js +405 -0
  387. package/lib/vendor/blamejs/lib/dora.js +402 -0
  388. package/lib/vendor/blamejs/lib/dr-runbook.js +368 -0
  389. package/lib/vendor/blamejs/lib/dsr.js +1188 -0
  390. package/lib/vendor/blamejs/lib/dual-control.js +526 -0
  391. package/lib/vendor/blamejs/lib/early-hints.js +212 -0
  392. package/lib/vendor/blamejs/lib/error-page.js +420 -0
  393. package/lib/vendor/blamejs/lib/events.js +214 -0
  394. package/lib/vendor/blamejs/lib/external-db-migrate.js +659 -0
  395. package/lib/vendor/blamejs/lib/external-db.js +1877 -0
  396. package/lib/vendor/blamejs/lib/fapi2.js +394 -0
  397. package/lib/vendor/blamejs/lib/fda-21cfr11.js +395 -0
  398. package/lib/vendor/blamejs/lib/fdx.js +370 -0
  399. package/lib/vendor/blamejs/lib/fedcm.js +264 -0
  400. package/lib/vendor/blamejs/lib/file-type.js +360 -0
  401. package/lib/vendor/blamejs/lib/file-upload.js +1256 -0
  402. package/lib/vendor/blamejs/lib/flag-cache.js +136 -0
  403. package/lib/vendor/blamejs/lib/flag-evaluation-context.js +135 -0
  404. package/lib/vendor/blamejs/lib/flag-providers.js +279 -0
  405. package/lib/vendor/blamejs/lib/flag-targeting.js +210 -0
  406. package/lib/vendor/blamejs/lib/flag.js +346 -0
  407. package/lib/vendor/blamejs/lib/forms.js +525 -0
  408. package/lib/vendor/blamejs/lib/framework-error.js +724 -0
  409. package/lib/vendor/blamejs/lib/framework-schema.js +845 -0
  410. package/lib/vendor/blamejs/lib/framework-sha1-hibp.js +34 -0
  411. package/lib/vendor/blamejs/lib/fsm.js +469 -0
  412. package/lib/vendor/blamejs/lib/gate-contract.js +1661 -0
  413. package/lib/vendor/blamejs/lib/gdpr-ropa.js +261 -0
  414. package/lib/vendor/blamejs/lib/graphql-federation.js +234 -0
  415. package/lib/vendor/blamejs/lib/guard-agent-registry.js +179 -0
  416. package/lib/vendor/blamejs/lib/guard-all.js +555 -0
  417. package/lib/vendor/blamejs/lib/guard-archive.js +901 -0
  418. package/lib/vendor/blamejs/lib/guard-auth.js +451 -0
  419. package/lib/vendor/blamejs/lib/guard-cidr.js +676 -0
  420. package/lib/vendor/blamejs/lib/guard-csv.js +1176 -0
  421. package/lib/vendor/blamejs/lib/guard-domain.js +814 -0
  422. package/lib/vendor/blamejs/lib/guard-dsn.js +382 -0
  423. package/lib/vendor/blamejs/lib/guard-email.js +951 -0
  424. package/lib/vendor/blamejs/lib/guard-envelope.js +294 -0
  425. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +217 -0
  426. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +150 -0
  427. package/lib/vendor/blamejs/lib/guard-filename.js +956 -0
  428. package/lib/vendor/blamejs/lib/guard-graphql.js +731 -0
  429. package/lib/vendor/blamejs/lib/guard-html-wcag-aria.js +164 -0
  430. package/lib/vendor/blamejs/lib/guard-html-wcag-forms.js +144 -0
  431. package/lib/vendor/blamejs/lib/guard-html-wcag-tables.js +154 -0
  432. package/lib/vendor/blamejs/lib/guard-html-wcag-tagwalk.js +44 -0
  433. package/lib/vendor/blamejs/lib/guard-html-wcag.js +470 -0
  434. package/lib/vendor/blamejs/lib/guard-html.js +1209 -0
  435. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +151 -0
  436. package/lib/vendor/blamejs/lib/guard-image.js +584 -0
  437. package/lib/vendor/blamejs/lib/guard-imap-command.js +337 -0
  438. package/lib/vendor/blamejs/lib/guard-jmap.js +321 -0
  439. package/lib/vendor/blamejs/lib/guard-json.js +935 -0
  440. package/lib/vendor/blamejs/lib/guard-jsonpath.js +512 -0
  441. package/lib/vendor/blamejs/lib/guard-jwt.js +772 -0
  442. package/lib/vendor/blamejs/lib/guard-list-id.js +318 -0
  443. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +412 -0
  444. package/lib/vendor/blamejs/lib/guard-mail-compose.js +282 -0
  445. package/lib/vendor/blamejs/lib/guard-mail-move.js +202 -0
  446. package/lib/vendor/blamejs/lib/guard-mail-query.js +310 -0
  447. package/lib/vendor/blamejs/lib/guard-mail-reply.js +172 -0
  448. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +207 -0
  449. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +566 -0
  450. package/lib/vendor/blamejs/lib/guard-markdown.js +768 -0
  451. package/lib/vendor/blamejs/lib/guard-message-id.js +267 -0
  452. package/lib/vendor/blamejs/lib/guard-mime.js +609 -0
  453. package/lib/vendor/blamejs/lib/guard-oauth.js +650 -0
  454. package/lib/vendor/blamejs/lib/guard-pdf.js +569 -0
  455. package/lib/vendor/blamejs/lib/guard-pop3-command.js +317 -0
  456. package/lib/vendor/blamejs/lib/guard-posture-chain.js +201 -0
  457. package/lib/vendor/blamejs/lib/guard-regex.js +632 -0
  458. package/lib/vendor/blamejs/lib/guard-saga-config.js +157 -0
  459. package/lib/vendor/blamejs/lib/guard-shell.js +522 -0
  460. package/lib/vendor/blamejs/lib/guard-smtp-command.js +594 -0
  461. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +168 -0
  462. package/lib/vendor/blamejs/lib/guard-stream-args.js +166 -0
  463. package/lib/vendor/blamejs/lib/guard-svg.js +1163 -0
  464. package/lib/vendor/blamejs/lib/guard-template.js +490 -0
  465. package/lib/vendor/blamejs/lib/guard-tenant-id.js +138 -0
  466. package/lib/vendor/blamejs/lib/guard-time.js +586 -0
  467. package/lib/vendor/blamejs/lib/guard-trace-context.js +172 -0
  468. package/lib/vendor/blamejs/lib/guard-uuid.js +548 -0
  469. package/lib/vendor/blamejs/lib/guard-xml.js +666 -0
  470. package/lib/vendor/blamejs/lib/guard-yaml.js +726 -0
  471. package/lib/vendor/blamejs/lib/hal.js +125 -0
  472. package/lib/vendor/blamejs/lib/handlers.js +350 -0
  473. package/lib/vendor/blamejs/lib/honeytoken.js +168 -0
  474. package/lib/vendor/blamejs/lib/html-balance.js +347 -0
  475. package/lib/vendor/blamejs/lib/http-client-cache.js +923 -0
  476. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +519 -0
  477. package/lib/vendor/blamejs/lib/http-client.js +2152 -0
  478. package/lib/vendor/blamejs/lib/http-message-signature.js +589 -0
  479. package/lib/vendor/blamejs/lib/http2-teardown.js +34 -0
  480. package/lib/vendor/blamejs/lib/i18n-messageformat.js +398 -0
  481. package/lib/vendor/blamejs/lib/i18n.js +931 -0
  482. package/lib/vendor/blamejs/lib/iab-mspa.js +257 -0
  483. package/lib/vendor/blamejs/lib/iab-tcf.js +461 -0
  484. package/lib/vendor/blamejs/lib/importmap-integrity.js +90 -0
  485. package/lib/vendor/blamejs/lib/inbox.js +435 -0
  486. package/lib/vendor/blamejs/lib/incident-report.js +314 -0
  487. package/lib/vendor/blamejs/lib/ip-utils.js +102 -0
  488. package/lib/vendor/blamejs/lib/jobs.js +185 -0
  489. package/lib/vendor/blamejs/lib/jose-jwe-experimental.js +228 -0
  490. package/lib/vendor/blamejs/lib/jsonapi.js +230 -0
  491. package/lib/vendor/blamejs/lib/keychain.js +865 -0
  492. package/lib/vendor/blamejs/lib/lazy-require.js +48 -0
  493. package/lib/vendor/blamejs/lib/legal-hold.js +374 -0
  494. package/lib/vendor/blamejs/lib/local-db-thin.js +321 -0
  495. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +369 -0
  496. package/lib/vendor/blamejs/lib/log-stream-local.js +146 -0
  497. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +410 -0
  498. package/lib/vendor/blamejs/lib/log-stream-otlp.js +286 -0
  499. package/lib/vendor/blamejs/lib/log-stream-syslog.js +310 -0
  500. package/lib/vendor/blamejs/lib/log-stream-webhook.js +199 -0
  501. package/lib/vendor/blamejs/lib/log-stream.js +584 -0
  502. package/lib/vendor/blamejs/lib/log.js +625 -0
  503. package/lib/vendor/blamejs/lib/lro.js +200 -0
  504. package/lib/vendor/blamejs/lib/mail-agent.js +786 -0
  505. package/lib/vendor/blamejs/lib/mail-arc-sign.js +417 -0
  506. package/lib/vendor/blamejs/lib/mail-arf.js +343 -0
  507. package/lib/vendor/blamejs/lib/mail-auth.js +2144 -0
  508. package/lib/vendor/blamejs/lib/mail-bimi.js +1047 -0
  509. package/lib/vendor/blamejs/lib/mail-bounce.js +955 -0
  510. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +1286 -0
  511. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +789 -0
  512. package/lib/vendor/blamejs/lib/mail-crypto.js +108 -0
  513. package/lib/vendor/blamejs/lib/mail-dav.js +1224 -0
  514. package/lib/vendor/blamejs/lib/mail-deploy.js +1119 -0
  515. package/lib/vendor/blamejs/lib/mail-dkim.js +1250 -0
  516. package/lib/vendor/blamejs/lib/mail-greylist.js +448 -0
  517. package/lib/vendor/blamejs/lib/mail-helo.js +473 -0
  518. package/lib/vendor/blamejs/lib/mail-journal.js +435 -0
  519. package/lib/vendor/blamejs/lib/mail-mdn.js +424 -0
  520. package/lib/vendor/blamejs/lib/mail-rbl.js +392 -0
  521. package/lib/vendor/blamejs/lib/mail-require-tls.js +198 -0
  522. package/lib/vendor/blamejs/lib/mail-scan.js +502 -0
  523. package/lib/vendor/blamejs/lib/mail-send-deliver.js +629 -0
  524. package/lib/vendor/blamejs/lib/mail-server-imap.js +1858 -0
  525. package/lib/vendor/blamejs/lib/mail-server-jmap.js +1565 -0
  526. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +908 -0
  527. package/lib/vendor/blamejs/lib/mail-server-mx.js +969 -0
  528. package/lib/vendor/blamejs/lib/mail-server-pop3.js +915 -0
  529. package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +315 -0
  530. package/lib/vendor/blamejs/lib/mail-server-registry.js +378 -0
  531. package/lib/vendor/blamejs/lib/mail-server-submission.js +1396 -0
  532. package/lib/vendor/blamejs/lib/mail-server-tls.js +445 -0
  533. package/lib/vendor/blamejs/lib/mail-sieve.js +557 -0
  534. package/lib/vendor/blamejs/lib/mail-spam-score.js +284 -0
  535. package/lib/vendor/blamejs/lib/mail-srs.js +248 -0
  536. package/lib/vendor/blamejs/lib/mail-store-fts.js +394 -0
  537. package/lib/vendor/blamejs/lib/mail-store.js +929 -0
  538. package/lib/vendor/blamejs/lib/mail-unsubscribe.js +400 -0
  539. package/lib/vendor/blamejs/lib/mail.js +1971 -0
  540. package/lib/vendor/blamejs/lib/mcp-tool-registry.js +473 -0
  541. package/lib/vendor/blamejs/lib/mcp.js +950 -0
  542. package/lib/vendor/blamejs/lib/metrics.js +1503 -0
  543. package/lib/vendor/blamejs/lib/middleware/age-gate.js +177 -0
  544. package/lib/vendor/blamejs/lib/middleware/ai-act-disclosure.js +203 -0
  545. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +981 -0
  546. package/lib/vendor/blamejs/lib/middleware/assetlinks.js +137 -0
  547. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +171 -0
  548. package/lib/vendor/blamejs/lib/middleware/attach-user.js +220 -0
  549. package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +293 -0
  550. package/lib/vendor/blamejs/lib/middleware/body-parser.js +1519 -0
  551. package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +183 -0
  552. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +217 -0
  553. package/lib/vendor/blamejs/lib/middleware/clear-site-data.js +122 -0
  554. package/lib/vendor/blamejs/lib/middleware/compose-pipeline.js +355 -0
  555. package/lib/vendor/blamejs/lib/middleware/compression.js +489 -0
  556. package/lib/vendor/blamejs/lib/middleware/cookies.js +130 -0
  557. package/lib/vendor/blamejs/lib/middleware/cors.js +386 -0
  558. package/lib/vendor/blamejs/lib/middleware/csp-nonce.js +388 -0
  559. package/lib/vendor/blamejs/lib/middleware/csp-report.js +167 -0
  560. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +499 -0
  561. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +243 -0
  562. package/lib/vendor/blamejs/lib/middleware/db-role-for.js +304 -0
  563. package/lib/vendor/blamejs/lib/middleware/dpop.js +402 -0
  564. package/lib/vendor/blamejs/lib/middleware/error-handler.js +69 -0
  565. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +168 -0
  566. package/lib/vendor/blamejs/lib/middleware/flag-context.js +110 -0
  567. package/lib/vendor/blamejs/lib/middleware/gpc.js +153 -0
  568. package/lib/vendor/blamejs/lib/middleware/headers.js +242 -0
  569. package/lib/vendor/blamejs/lib/middleware/health.js +438 -0
  570. package/lib/vendor/blamejs/lib/middleware/host-allowlist.js +189 -0
  571. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +964 -0
  572. package/lib/vendor/blamejs/lib/middleware/index.js +183 -0
  573. package/lib/vendor/blamejs/lib/middleware/nel.js +214 -0
  574. package/lib/vendor/blamejs/lib/middleware/network-allowlist.js +237 -0
  575. package/lib/vendor/blamejs/lib/middleware/no-cache.js +106 -0
  576. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +177 -0
  577. package/lib/vendor/blamejs/lib/middleware/protected-resource-metadata.js +277 -0
  578. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +556 -0
  579. package/lib/vendor/blamejs/lib/middleware/request-id.js +79 -0
  580. package/lib/vendor/blamejs/lib/middleware/request-log.js +205 -0
  581. package/lib/vendor/blamejs/lib/middleware/require-aal.js +138 -0
  582. package/lib/vendor/blamejs/lib/middleware/require-auth.js +144 -0
  583. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +290 -0
  584. package/lib/vendor/blamejs/lib/middleware/require-content-type.js +113 -0
  585. package/lib/vendor/blamejs/lib/middleware/require-methods.js +97 -0
  586. package/lib/vendor/blamejs/lib/middleware/require-mtls.js +212 -0
  587. package/lib/vendor/blamejs/lib/middleware/require-step-up.js +226 -0
  588. package/lib/vendor/blamejs/lib/middleware/scim-server.js +375 -0
  589. package/lib/vendor/blamejs/lib/middleware/security-headers.js +285 -0
  590. package/lib/vendor/blamejs/lib/middleware/security-txt.js +170 -0
  591. package/lib/vendor/blamejs/lib/middleware/span-http-server.js +280 -0
  592. package/lib/vendor/blamejs/lib/middleware/speculation-rules.js +323 -0
  593. package/lib/vendor/blamejs/lib/middleware/sse.js +200 -0
  594. package/lib/vendor/blamejs/lib/middleware/trace-log-correlation.js +167 -0
  595. package/lib/vendor/blamejs/lib/middleware/trace-propagate.js +148 -0
  596. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +749 -0
  597. package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +164 -0
  598. package/lib/vendor/blamejs/lib/migration-files.js +37 -0
  599. package/lib/vendor/blamejs/lib/migrations.js +385 -0
  600. package/lib/vendor/blamejs/lib/mime-parse.js +198 -0
  601. package/lib/vendor/blamejs/lib/money.js +699 -0
  602. package/lib/vendor/blamejs/lib/mtls-ca.js +572 -0
  603. package/lib/vendor/blamejs/lib/mtls-engine-default.js +501 -0
  604. package/lib/vendor/blamejs/lib/network-byte-quota.js +308 -0
  605. package/lib/vendor/blamejs/lib/network-dns-resolver.js +533 -0
  606. package/lib/vendor/blamejs/lib/network-dns.js +1930 -0
  607. package/lib/vendor/blamejs/lib/network-heartbeat.js +425 -0
  608. package/lib/vendor/blamejs/lib/network-nts.js +574 -0
  609. package/lib/vendor/blamejs/lib/network-proxy.js +265 -0
  610. package/lib/vendor/blamejs/lib/network-smtp-policy.js +836 -0
  611. package/lib/vendor/blamejs/lib/network-tls.js +3126 -0
  612. package/lib/vendor/blamejs/lib/network.js +346 -0
  613. package/lib/vendor/blamejs/lib/nis2-report.js +181 -0
  614. package/lib/vendor/blamejs/lib/nist-crosswalk.js +293 -0
  615. package/lib/vendor/blamejs/lib/nonce-store.js +177 -0
  616. package/lib/vendor/blamejs/lib/notify.js +683 -0
  617. package/lib/vendor/blamejs/lib/ntp-check.js +458 -0
  618. package/lib/vendor/blamejs/lib/numeric-bounds.js +111 -0
  619. package/lib/vendor/blamejs/lib/numeric-checks.js +40 -0
  620. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +349 -0
  621. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +488 -0
  622. package/lib/vendor/blamejs/lib/object-store/gcs-bucket-ops.js +351 -0
  623. package/lib/vendor/blamejs/lib/object-store/gcs.js +515 -0
  624. package/lib/vendor/blamejs/lib/object-store/http-put.js +153 -0
  625. package/lib/vendor/blamejs/lib/object-store/http-request.js +38 -0
  626. package/lib/vendor/blamejs/lib/object-store/index.js +197 -0
  627. package/lib/vendor/blamejs/lib/object-store/local.js +163 -0
  628. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +1133 -0
  629. package/lib/vendor/blamejs/lib/object-store/sigv4.js +957 -0
  630. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +420 -0
  631. package/lib/vendor/blamejs/lib/observability-tracer.js +395 -0
  632. package/lib/vendor/blamejs/lib/observability.js +720 -0
  633. package/lib/vendor/blamejs/lib/openapi-paths-builder.js +248 -0
  634. package/lib/vendor/blamejs/lib/openapi-schema-walk.js +192 -0
  635. package/lib/vendor/blamejs/lib/openapi-security.js +169 -0
  636. package/lib/vendor/blamejs/lib/openapi-yaml.js +154 -0
  637. package/lib/vendor/blamejs/lib/openapi.js +489 -0
  638. package/lib/vendor/blamejs/lib/otel-export.js +278 -0
  639. package/lib/vendor/blamejs/lib/outbox.js +547 -0
  640. package/lib/vendor/blamejs/lib/pagination.js +542 -0
  641. package/lib/vendor/blamejs/lib/parsers/index.js +91 -0
  642. package/lib/vendor/blamejs/lib/parsers/safe-env.js +642 -0
  643. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +293 -0
  644. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +784 -0
  645. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +390 -0
  646. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +1015 -0
  647. package/lib/vendor/blamejs/lib/permissions.js +793 -0
  648. package/lib/vendor/blamejs/lib/pick.js +105 -0
  649. package/lib/vendor/blamejs/lib/pqc-agent.js +351 -0
  650. package/lib/vendor/blamejs/lib/pqc-gate.js +279 -0
  651. package/lib/vendor/blamejs/lib/pqc-software.js +271 -0
  652. package/lib/vendor/blamejs/lib/problem-details.js +482 -0
  653. package/lib/vendor/blamejs/lib/process-spawn.js +196 -0
  654. package/lib/vendor/blamejs/lib/promise-pool.js +162 -0
  655. package/lib/vendor/blamejs/lib/protobuf-encoder.js +190 -0
  656. package/lib/vendor/blamejs/lib/protocol-dispatcher.js +161 -0
  657. package/lib/vendor/blamejs/lib/public-suffix.js +403 -0
  658. package/lib/vendor/blamejs/lib/pubsub-cluster.js +154 -0
  659. package/lib/vendor/blamejs/lib/pubsub-redis.js +167 -0
  660. package/lib/vendor/blamejs/lib/pubsub.js +463 -0
  661. package/lib/vendor/blamejs/lib/queue-local.js +476 -0
  662. package/lib/vendor/blamejs/lib/queue-redis.js +745 -0
  663. package/lib/vendor/blamejs/lib/queue-sqs.js +319 -0
  664. package/lib/vendor/blamejs/lib/queue.js +1016 -0
  665. package/lib/vendor/blamejs/lib/redact.js +1007 -0
  666. package/lib/vendor/blamejs/lib/redis-client.js +520 -0
  667. package/lib/vendor/blamejs/lib/render.js +285 -0
  668. package/lib/vendor/blamejs/lib/request-helpers.js +767 -0
  669. package/lib/vendor/blamejs/lib/resource-access-lock.js +116 -0
  670. package/lib/vendor/blamejs/lib/restore-bundle.js +340 -0
  671. package/lib/vendor/blamejs/lib/restore-rollback.js +365 -0
  672. package/lib/vendor/blamejs/lib/restore.js +409 -0
  673. package/lib/vendor/blamejs/lib/retention.js +640 -0
  674. package/lib/vendor/blamejs/lib/retry.js +523 -0
  675. package/lib/vendor/blamejs/lib/router.js +1289 -0
  676. package/lib/vendor/blamejs/lib/safe-async.js +1184 -0
  677. package/lib/vendor/blamejs/lib/safe-buffer.js +562 -0
  678. package/lib/vendor/blamejs/lib/safe-decompress.js +297 -0
  679. package/lib/vendor/blamejs/lib/safe-dns.js +665 -0
  680. package/lib/vendor/blamejs/lib/safe-ical.js +634 -0
  681. package/lib/vendor/blamejs/lib/safe-icap.js +502 -0
  682. package/lib/vendor/blamejs/lib/safe-json.js +946 -0
  683. package/lib/vendor/blamejs/lib/safe-jsonpath.js +285 -0
  684. package/lib/vendor/blamejs/lib/safe-mime.js +831 -0
  685. package/lib/vendor/blamejs/lib/safe-mount-info.js +306 -0
  686. package/lib/vendor/blamejs/lib/safe-path.js +254 -0
  687. package/lib/vendor/blamejs/lib/safe-redirect.js +106 -0
  688. package/lib/vendor/blamejs/lib/safe-schema.js +1810 -0
  689. package/lib/vendor/blamejs/lib/safe-sieve.js +684 -0
  690. package/lib/vendor/blamejs/lib/safe-smtp.js +185 -0
  691. package/lib/vendor/blamejs/lib/safe-sql.js +363 -0
  692. package/lib/vendor/blamejs/lib/safe-url.js +428 -0
  693. package/lib/vendor/blamejs/lib/safe-vcard.js +473 -0
  694. package/lib/vendor/blamejs/lib/sandbox-worker.js +135 -0
  695. package/lib/vendor/blamejs/lib/sandbox.js +358 -0
  696. package/lib/vendor/blamejs/lib/scheduler.js +827 -0
  697. package/lib/vendor/blamejs/lib/sd-notify.js +269 -0
  698. package/lib/vendor/blamejs/lib/sec-cyber.js +214 -0
  699. package/lib/vendor/blamejs/lib/security-assert.js +395 -0
  700. package/lib/vendor/blamejs/lib/seeders.js +620 -0
  701. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +309 -0
  702. package/lib/vendor/blamejs/lib/self-update.js +804 -0
  703. package/lib/vendor/blamejs/lib/server-timing.js +174 -0
  704. package/lib/vendor/blamejs/lib/session-device-binding.js +431 -0
  705. package/lib/vendor/blamejs/lib/session-stores.js +138 -0
  706. package/lib/vendor/blamejs/lib/session.js +1162 -0
  707. package/lib/vendor/blamejs/lib/slug.js +381 -0
  708. package/lib/vendor/blamejs/lib/sse.js +349 -0
  709. package/lib/vendor/blamejs/lib/ssrf-guard.js +792 -0
  710. package/lib/vendor/blamejs/lib/standard-webhooks.js +183 -0
  711. package/lib/vendor/blamejs/lib/static.js +1249 -0
  712. package/lib/vendor/blamejs/lib/storage.js +1272 -0
  713. package/lib/vendor/blamejs/lib/stream-throttle.js +235 -0
  714. package/lib/vendor/blamejs/lib/structured-fields.js +244 -0
  715. package/lib/vendor/blamejs/lib/subject.js +667 -0
  716. package/lib/vendor/blamejs/lib/tcpa-10dlc.js +175 -0
  717. package/lib/vendor/blamejs/lib/template.js +931 -0
  718. package/lib/vendor/blamejs/lib/tenant-quota.js +545 -0
  719. package/lib/vendor/blamejs/lib/test-harness.js +275 -0
  720. package/lib/vendor/blamejs/lib/testing.js +1185 -0
  721. package/lib/vendor/blamejs/lib/time.js +578 -0
  722. package/lib/vendor/blamejs/lib/tls-exporter.js +239 -0
  723. package/lib/vendor/blamejs/lib/totp.js +318 -0
  724. package/lib/vendor/blamejs/lib/tracing.js +546 -0
  725. package/lib/vendor/blamejs/lib/uuid.js +207 -0
  726. package/lib/vendor/blamejs/lib/validate-opts.js +381 -0
  727. package/lib/vendor/blamejs/lib/vault/index.js +638 -0
  728. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +311 -0
  729. package/lib/vendor/blamejs/lib/vault/passphrase-source.js +198 -0
  730. package/lib/vendor/blamejs/lib/vault/rotate.js +803 -0
  731. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +471 -0
  732. package/lib/vendor/blamejs/lib/vault/wrap.js +296 -0
  733. package/lib/vendor/blamejs/lib/vault-aad.js +259 -0
  734. package/lib/vendor/blamejs/lib/vendor/.vendor-data-pubkey +4 -0
  735. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +161 -0
  736. package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.data.js +68 -0
  737. package/lib/vendor/blamejs/lib/vendor/bimi-trust-anchors.pem +33 -0
  738. package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.data.js +1325 -0
  739. package/lib/vendor/blamejs/lib/vendor/common-passwords-top-10000.txt +10002 -0
  740. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +9 -0
  741. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +18 -0
  742. package/lib/vendor/blamejs/lib/vendor/pki.cjs +181 -0
  743. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +16382 -0
  744. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5881 -0
  745. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +328 -0
  746. package/lib/vendor/blamejs/lib/vendor/vendor-data-pubkey.js +16 -0
  747. package/lib/vendor/blamejs/lib/vendor-data.js +520 -0
  748. package/lib/vendor/blamejs/lib/vex.js +630 -0
  749. package/lib/vendor/blamejs/lib/watcher.js +608 -0
  750. package/lib/vendor/blamejs/lib/web-push-vapid.js +322 -0
  751. package/lib/vendor/blamejs/lib/webhook.js +977 -0
  752. package/lib/vendor/blamejs/lib/websocket-channels.js +327 -0
  753. package/lib/vendor/blamejs/lib/websocket.js +1561 -0
  754. package/lib/vendor/blamejs/lib/wiki-concepts.js +338 -0
  755. package/lib/vendor/blamejs/lib/worker-pool.js +464 -0
  756. package/lib/vendor/blamejs/lib/ws-client.js +978 -0
  757. package/lib/vendor/blamejs/lib/xml-c14n.js +506 -0
  758. package/lib/vendor/blamejs/memory/specs/node-26-map-getorinsert-migration.md +164 -0
  759. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +19 -0
  760. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/README.md +88 -0
  761. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/build.sh +26 -0
  762. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/project.yaml +28 -0
  763. package/lib/vendor/blamejs/package.json +81 -0
  764. package/lib/vendor/blamejs/release-notes/v0.0.x.json +310 -0
  765. package/lib/vendor/blamejs/release-notes/v0.1.x.json +1798 -0
  766. package/lib/vendor/blamejs/release-notes/v0.10.x.json +1288 -0
  767. package/lib/vendor/blamejs/release-notes/v0.11.x.json +2551 -0
  768. package/lib/vendor/blamejs/release-notes/v0.12.0.json +64 -0
  769. package/lib/vendor/blamejs/release-notes/v0.12.1.json +32 -0
  770. package/lib/vendor/blamejs/release-notes/v0.12.2.json +45 -0
  771. package/lib/vendor/blamejs/release-notes/v0.2.x.json +706 -0
  772. package/lib/vendor/blamejs/release-notes/v0.3.x.json +786 -0
  773. package/lib/vendor/blamejs/release-notes/v0.4.x.json +588 -0
  774. package/lib/vendor/blamejs/release-notes/v0.5.x.json +390 -0
  775. package/lib/vendor/blamejs/release-notes/v0.6.x.json +1947 -0
  776. package/lib/vendor/blamejs/release-notes/v0.7.x.json +3811 -0
  777. package/lib/vendor/blamejs/release-notes/v0.8.x.json +3318 -0
  778. package/lib/vendor/blamejs/release-notes/v0.9.x.json +2257 -0
  779. package/lib/vendor/blamejs/scripts/build-vendored-sbom.js +325 -0
  780. package/lib/vendor/blamejs/scripts/check-api-snapshot.js +62 -0
  781. package/lib/vendor/blamejs/scripts/check-changelog-extract.js +108 -0
  782. package/lib/vendor/blamejs/scripts/check-pack-against-gitignore.js +83 -0
  783. package/lib/vendor/blamejs/scripts/check-services.js +483 -0
  784. package/lib/vendor/blamejs/scripts/check-vendor-currency.js +349 -0
  785. package/lib/vendor/blamejs/scripts/consolidate-release-notes.js +216 -0
  786. package/lib/vendor/blamejs/scripts/gen-migrating.js +275 -0
  787. package/lib/vendor/blamejs/scripts/generate-changelog-entry.js +577 -0
  788. package/lib/vendor/blamejs/scripts/generate-release-signing-key.js +79 -0
  789. package/lib/vendor/blamejs/scripts/publish-dep-confusion-placeholder.sh +101 -0
  790. package/lib/vendor/blamejs/scripts/refresh-api-snapshot.js +31 -0
  791. package/lib/vendor/blamejs/scripts/refresh-vendor-manifest.js +132 -0
  792. package/lib/vendor/blamejs/scripts/release.js +652 -0
  793. package/lib/vendor/blamejs/scripts/sha3-digest.js +62 -0
  794. package/lib/vendor/blamejs/scripts/sign-release-artifact.js +92 -0
  795. package/lib/vendor/blamejs/scripts/test-integration.js +181 -0
  796. package/lib/vendor/blamejs/scripts/test-wiki-integration.js +126 -0
  797. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +77 -0
  798. package/lib/vendor/blamejs/scripts/vendor-data-gen.js +186 -0
  799. package/lib/vendor/blamejs/scripts/vendor-data-keygen.js +101 -0
  800. package/lib/vendor/blamejs/scripts/vendor-update.sh +278 -0
  801. package/lib/vendor/blamejs/test/00-primitives.js +19075 -0
  802. package/lib/vendor/blamejs/test/10-state.js +622 -0
  803. package/lib/vendor/blamejs/test/20-db.js +561 -0
  804. package/lib/vendor/blamejs/test/30-chain.js +2110 -0
  805. package/lib/vendor/blamejs/test/40-consumers.js +2453 -0
  806. package/lib/vendor/blamejs/test/50-integration.js +486 -0
  807. package/lib/vendor/blamejs/test/_helpers.js +10 -0
  808. package/lib/vendor/blamejs/test/_smoke-worker.js +69 -0
  809. package/lib/vendor/blamejs/test/fixtures/exploit-corpus/corpus.json +368 -0
  810. package/lib/vendor/blamejs/test/fixtures/http-client-stream-payload.txt +2 -0
  811. package/lib/vendor/blamejs/test/fixtures/worker-pool/echo.js +52 -0
  812. package/lib/vendor/blamejs/test/helpers/_codebase-shingle-worker.js +24 -0
  813. package/lib/vendor/blamejs/test/helpers/_codebase-shingle.js +203 -0
  814. package/lib/vendor/blamejs/test/helpers/_shape-match.js +513 -0
  815. package/lib/vendor/blamejs/test/helpers/check.js +36 -0
  816. package/lib/vendor/blamejs/test/helpers/cluster.js +70 -0
  817. package/lib/vendor/blamejs/test/helpers/db.js +143 -0
  818. package/lib/vendor/blamejs/test/helpers/drivers.js +207 -0
  819. package/lib/vendor/blamejs/test/helpers/fs-watch.js +101 -0
  820. package/lib/vendor/blamejs/test/helpers/http.js +14 -0
  821. package/lib/vendor/blamejs/test/helpers/index.js +93 -0
  822. package/lib/vendor/blamejs/test/helpers/json-round-trip.js +120 -0
  823. package/lib/vendor/blamejs/test/helpers/mocks.js +20 -0
  824. package/lib/vendor/blamejs/test/helpers/otel.js +13 -0
  825. package/lib/vendor/blamejs/test/helpers/services.js +380 -0
  826. package/lib/vendor/blamejs/test/helpers/wait.js +206 -0
  827. package/lib/vendor/blamejs/test/integration/cache.test.js +235 -0
  828. package/lib/vendor/blamejs/test/integration/cluster-provider-mysql.test.js +174 -0
  829. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +611 -0
  830. package/lib/vendor/blamejs/test/integration/http-client.test.js +129 -0
  831. package/lib/vendor/blamejs/test/integration/log-stream.test.js +219 -0
  832. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +181 -0
  833. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +152 -0
  834. package/lib/vendor/blamejs/test/integration/mail-smtp.test.js +161 -0
  835. package/lib/vendor/blamejs/test/integration/mtls-ca.test.js +289 -0
  836. package/lib/vendor/blamejs/test/integration/network-dns.test.js +123 -0
  837. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +101 -0
  838. package/lib/vendor/blamejs/test/integration/ntp-check.test.js +89 -0
  839. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +403 -0
  840. package/lib/vendor/blamejs/test/integration/pqc-pkcs8-forward-compat.test.js +271 -0
  841. package/lib/vendor/blamejs/test/integration/pubsub.test.js +137 -0
  842. package/lib/vendor/blamejs/test/integration/queue-redis.test.js +352 -0
  843. package/lib/vendor/blamejs/test/integration/redis-client-tls.test.js +96 -0
  844. package/lib/vendor/blamejs/test/integration/ssrf-guard.test.js +98 -0
  845. package/lib/vendor/blamejs/test/integration/websocket-permessage-deflate.test.js +261 -0
  846. package/lib/vendor/blamejs/test/integration/ws-client-roundtrip.test.js +230 -0
  847. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +211 -0
  848. package/lib/vendor/blamejs/test/layer-0-primitives/a2a.test.js +59 -0
  849. package/lib/vendor/blamejs/test/layer-0-primitives/access-lock.test.js +136 -0
  850. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +219 -0
  851. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +69 -0
  852. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +266 -0
  853. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +262 -0
  854. package/lib/vendor/blamejs/test/layer-0-primitives/agent-orchestrator.test.js +390 -0
  855. package/lib/vendor/blamejs/test/layer-0-primitives/agent-posture-chain.test.js +174 -0
  856. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +279 -0
  857. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +322 -0
  858. package/lib/vendor/blamejs/test/layer-0-primitives/agent-stream.test.js +227 -0
  859. package/lib/vendor/blamejs/test/layer-0-primitives/agent-tenant.test.js +302 -0
  860. package/lib/vendor/blamejs/test/layer-0-primitives/agent-trace.test.js +150 -0
  861. package/lib/vendor/blamejs/test/layer-0-primitives/ai-adverse-decision.test.js +44 -0
  862. package/lib/vendor/blamejs/test/layer-0-primitives/ai-content-detect.test.js +150 -0
  863. package/lib/vendor/blamejs/test/layer-0-primitives/ai-input.test.js +50 -0
  864. package/lib/vendor/blamejs/test/layer-0-primitives/ai-model-manifest.test.js +96 -0
  865. package/lib/vendor/blamejs/test/layer-0-primitives/ai-pref.test.js +76 -0
  866. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +1080 -0
  867. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +311 -0
  868. package/lib/vendor/blamejs/test/layer-0-primitives/archive-zip-stream.test.js +291 -0
  869. package/lib/vendor/blamejs/test/layer-0-primitives/archive.test.js +140 -0
  870. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +267 -0
  871. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +108 -0
  872. package/lib/vendor/blamejs/test/layer-0-primitives/asyncapi.test.js +929 -0
  873. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-conflict-path.test.js +80 -0
  874. package/lib/vendor/blamejs/test/layer-0-primitives/audit-cve-defensive.test.js +176 -0
  875. package/lib/vendor/blamejs/test/layer-0-primitives/audit-daily-review.test.js +132 -0
  876. package/lib/vendor/blamejs/test/layer-0-primitives/audit-export-cadf.test.js +97 -0
  877. package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +141 -0
  878. package/lib/vendor/blamejs/test/layer-0-primitives/audit-segregation.test.js +115 -0
  879. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-ml-dsa-65.test.js +163 -0
  880. package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +246 -0
  881. package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge-verifier.test.js +485 -0
  882. package/lib/vendor/blamejs/test/layer-0-primitives/auth-bot-challenge.test.js +331 -0
  883. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +352 -0
  884. package/lib/vendor/blamejs/test/layer-0-primitives/auth-lockout.test.js +572 -0
  885. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password-audit.test.js +61 -0
  886. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-bucket-ops.test.js +258 -0
  887. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +105 -0
  888. package/lib/vendor/blamejs/test/layer-0-primitives/backup-worker.test.js +34 -0
  889. package/lib/vendor/blamejs/test/layer-0-primitives/bearer-auth.test.js +107 -0
  890. package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-chunked-malformed.test.js +131 -0
  891. package/lib/vendor/blamejs/test/layer-0-primitives/body-parser-smuggling.test.js +118 -0
  892. package/lib/vendor/blamejs/test/layer-0-primitives/boot-gates.test.js +85 -0
  893. package/lib/vendor/blamejs/test/layer-0-primitives/breach-deadline.test.js +38 -0
  894. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +861 -0
  895. package/lib/vendor/blamejs/test/layer-0-primitives/budr.test.js +55 -0
  896. package/lib/vendor/blamejs/test/layer-0-primitives/bundler-engine.test.js +209 -0
  897. package/lib/vendor/blamejs/test/layer-0-primitives/cache-status.test.js +129 -0
  898. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +871 -0
  899. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +891 -0
  900. package/lib/vendor/blamejs/test/layer-0-primitives/canonical-json-jcs.test.js +43 -0
  901. package/lib/vendor/blamejs/test/layer-0-primitives/cdn-cache-control.test.js +243 -0
  902. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +550 -0
  903. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +107 -0
  904. package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +147 -0
  905. package/lib/vendor/blamejs/test/layer-0-primitives/cli-audit-verify-chain.test.js +104 -0
  906. package/lib/vendor/blamejs/test/layer-0-primitives/cli-backup.test.js +135 -0
  907. package/lib/vendor/blamejs/test/layer-0-primitives/cli-config-drift.test.js +67 -0
  908. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +75 -0
  909. package/lib/vendor/blamejs/test/layer-0-primitives/cli-file-type.test.js +98 -0
  910. package/lib/vendor/blamejs/test/layer-0-primitives/cli-helpers.test.js +145 -0
  911. package/lib/vendor/blamejs/test/layer-0-primitives/cli-mtls.test.js +133 -0
  912. package/lib/vendor/blamejs/test/layer-0-primitives/cli-password.test.js +97 -0
  913. package/lib/vendor/blamejs/test/layer-0-primitives/cli-restore.test.js +160 -0
  914. package/lib/vendor/blamejs/test/layer-0-primitives/cli-retention.test.js +84 -0
  915. package/lib/vendor/blamejs/test/layer-0-primitives/cli-security.test.js +69 -0
  916. package/lib/vendor/blamejs/test/layer-0-primitives/cli-vault.test.js +142 -0
  917. package/lib/vendor/blamejs/test/layer-0-primitives/client-hints.test.js +133 -0
  918. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +237 -0
  919. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +9600 -0
  920. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +575 -0
  921. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-cascade.test.js +89 -0
  922. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-eaa.test.js +36 -0
  923. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +712 -0
  924. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +278 -0
  925. package/lib/vendor/blamejs/test/layer-0-primitives/config-drift.test.js +97 -0
  926. package/lib/vendor/blamejs/test/layer-0-primitives/config.test.js +424 -0
  927. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +94 -0
  928. package/lib/vendor/blamejs/test/layer-0-primitives/cors.test.js +357 -0
  929. package/lib/vendor/blamejs/test/layer-0-primitives/cra-report.test.js +31 -0
  930. package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +226 -0
  931. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +86 -0
  932. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-envelope.test.js +85 -0
  933. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +193 -0
  934. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +98 -0
  935. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke-pq.test.js +132 -0
  936. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hpke.test.js +155 -0
  937. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-mlkem768-x25519.test.js +129 -0
  938. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-namespace-hash.test.js +0 -0
  939. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-random-int.test.js +72 -0
  940. package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +96 -0
  941. package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +401 -0
  942. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +34 -0
  943. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +180 -0
  944. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +210 -0
  945. package/lib/vendor/blamejs/test/layer-0-primitives/daily-byte-quota.test.js +153 -0
  946. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +66 -0
  947. package/lib/vendor/blamejs/test/layer-0-primitives/data-act.test.js +74 -0
  948. package/lib/vendor/blamejs/test/layer-0-primitives/db-collection-extensions.test.js +226 -0
  949. package/lib/vendor/blamejs/test/layer-0-primitives/db-collection.test.js +136 -0
  950. package/lib/vendor/blamejs/test/layer-0-primitives/db-init-extensions.test.js +165 -0
  951. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +150 -0
  952. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-extensions.test.js +191 -0
  953. package/lib/vendor/blamejs/test/layer-0-primitives/db-role-for.test.js +228 -0
  954. package/lib/vendor/blamejs/test/layer-0-primitives/db-vacuum.test.js +55 -0
  955. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +89 -0
  956. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +184 -0
  957. package/lib/vendor/blamejs/test/layer-0-primitives/declare-row-policy.test.js +203 -0
  958. package/lib/vendor/blamejs/test/layer-0-primitives/declare-view.test.js +303 -0
  959. package/lib/vendor/blamejs/test/layer-0-primitives/dns-dnssec-algorithm.test.js +163 -0
  960. package/lib/vendor/blamejs/test/layer-0-primitives/dns-null-mx.test.js +39 -0
  961. package/lib/vendor/blamejs/test/layer-0-primitives/dora.test.js +165 -0
  962. package/lib/vendor/blamejs/test/layer-0-primitives/dr-runbook.test.js +59 -0
  963. package/lib/vendor/blamejs/test/layer-0-primitives/dsr-state-rules.test.js +55 -0
  964. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +786 -0
  965. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +105 -0
  966. package/lib/vendor/blamejs/test/layer-0-primitives/early-hints.test.js +147 -0
  967. package/lib/vendor/blamejs/test/layer-0-primitives/events.test.js +105 -0
  968. package/lib/vendor/blamejs/test/layer-0-primitives/exploit-replay.test.js +243 -0
  969. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +181 -0
  970. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +190 -0
  971. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-routing.test.js +531 -0
  972. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +118 -0
  973. package/lib/vendor/blamejs/test/layer-0-primitives/fapi2.test.js +89 -0
  974. package/lib/vendor/blamejs/test/layer-0-primitives/fda-21cfr11.test.js +156 -0
  975. package/lib/vendor/blamejs/test/layer-0-primitives/fdx.test.js +79 -0
  976. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +216 -0
  977. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +434 -0
  978. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +432 -0
  979. package/lib/vendor/blamejs/test/layer-0-primitives/file-type.test.js +81 -0
  980. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +887 -0
  981. package/lib/vendor/blamejs/test/layer-0-primitives/forensic-snapshot.test.js +51 -0
  982. package/lib/vendor/blamejs/test/layer-0-primitives/fsm.test.js +375 -0
  983. package/lib/vendor/blamejs/test/layer-0-primitives/gcs-bucket-ops.test.js +321 -0
  984. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +41 -0
  985. package/lib/vendor/blamejs/test/layer-0-primitives/graphql-federation.test.js +32 -0
  986. package/lib/vendor/blamejs/test/layer-0-primitives/guard-agent-registry.test.js +87 -0
  987. package/lib/vendor/blamejs/test/layer-0-primitives/guard-all.test.js +328 -0
  988. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +339 -0
  989. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +694 -0
  990. package/lib/vendor/blamejs/test/layer-0-primitives/guard-dsn.test.js +296 -0
  991. package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +234 -0
  992. package/lib/vendor/blamejs/test/layer-0-primitives/guard-envelope.test.js +192 -0
  993. package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-payload.test.js +89 -0
  994. package/lib/vendor/blamejs/test/layer-0-primitives/guard-event-bus-topic.test.js +71 -0
  995. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +386 -0
  996. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html-wcag.test.js +859 -0
  997. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +357 -0
  998. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +92 -0
  999. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  1000. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +174 -0
  1001. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +317 -0
  1002. package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-id.test.js +199 -0
  1003. package/lib/vendor/blamejs/test/layer-0-primitives/guard-list-unsubscribe.test.js +214 -0
  1004. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-compose.test.js +111 -0
  1005. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-move.test.js +110 -0
  1006. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-query.test.js +112 -0
  1007. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-reply.test.js +86 -0
  1008. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mail-sieve.test.js +92 -0
  1009. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +301 -0
  1010. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +265 -0
  1011. package/lib/vendor/blamejs/test/layer-0-primitives/guard-message-id.test.js +0 -0
  1012. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +161 -0
  1013. package/lib/vendor/blamejs/test/layer-0-primitives/guard-posture-chain.test.js +100 -0
  1014. package/lib/vendor/blamejs/test/layer-0-primitives/guard-saga-config.test.js +79 -0
  1015. package/lib/vendor/blamejs/test/layer-0-primitives/guard-smtp-command.test.js +269 -0
  1016. package/lib/vendor/blamejs/test/layer-0-primitives/guard-snapshot-envelope.test.js +89 -0
  1017. package/lib/vendor/blamejs/test/layer-0-primitives/guard-stream-args.test.js +78 -0
  1018. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +288 -0
  1019. package/lib/vendor/blamejs/test/layer-0-primitives/guard-tenant-id.test.js +69 -0
  1020. package/lib/vendor/blamejs/test/layer-0-primitives/guard-trace-context.test.js +102 -0
  1021. package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +202 -0
  1022. package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +203 -0
  1023. package/lib/vendor/blamejs/test/layer-0-primitives/hal.test.js +51 -0
  1024. package/lib/vendor/blamejs/test/layer-0-primitives/honeytoken.test.js +50 -0
  1025. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +37 -0
  1026. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +692 -0
  1027. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +280 -0
  1028. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +225 -0
  1029. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +203 -0
  1030. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +991 -0
  1031. package/lib/vendor/blamejs/test/layer-0-primitives/iab-mspa.test.js +63 -0
  1032. package/lib/vendor/blamejs/test/layer-0-primitives/iab-tcf.test.js +73 -0
  1033. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +612 -0
  1034. package/lib/vendor/blamejs/test/layer-0-primitives/importmap-integrity.test.js +56 -0
  1035. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +166 -0
  1036. package/lib/vendor/blamejs/test/layer-0-primitives/incident-report.test.js +29 -0
  1037. package/lib/vendor/blamejs/test/layer-0-primitives/jose-jwe-experimental.test.js +121 -0
  1038. package/lib/vendor/blamejs/test/layer-0-primitives/json-api.test.js +58 -0
  1039. package/lib/vendor/blamejs/test/layer-0-primitives/json-round-trip-helper.test.js +110 -0
  1040. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +159 -0
  1041. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  1042. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +118 -0
  1043. package/lib/vendor/blamejs/test/layer-0-primitives/local-db-thin.test.js +150 -0
  1044. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-cloudwatch.test.js +489 -0
  1045. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp-grpc.test.js +207 -0
  1046. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream-otlp.test.js +283 -0
  1047. package/lib/vendor/blamejs/test/layer-0-primitives/lro.test.js +65 -0
  1048. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +417 -0
  1049. package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +208 -0
  1050. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +910 -0
  1051. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +502 -0
  1052. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +680 -0
  1053. package/lib/vendor/blamejs/test/layer-0-primitives/mail-canspam.test.js +128 -0
  1054. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +149 -0
  1055. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +323 -0
  1056. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +297 -0
  1057. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +514 -0
  1058. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy-tlsrpt.test.js +369 -0
  1059. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +199 -0
  1060. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +627 -0
  1061. package/lib/vendor/blamejs/test/layer-0-primitives/mail-feedback-id.test.js +56 -0
  1062. package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +217 -0
  1063. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +283 -0
  1064. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +217 -0
  1065. package/lib/vendor/blamejs/test/layer-0-primitives/mail-mdn.test.js +334 -0
  1066. package/lib/vendor/blamejs/test/layer-0-primitives/mail-rbl.test.js +271 -0
  1067. package/lib/vendor/blamejs/test/layer-0-primitives/mail-require-tls.test.js +128 -0
  1068. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +215 -0
  1069. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +336 -0
  1070. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +732 -0
  1071. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +840 -0
  1072. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +130 -0
  1073. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +285 -0
  1074. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +74 -0
  1075. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +112 -0
  1076. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +229 -0
  1077. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +394 -0
  1078. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +147 -0
  1079. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +151 -0
  1080. package/lib/vendor/blamejs/test/layer-0-primitives/mail-spam-score.test.js +204 -0
  1081. package/lib/vendor/blamejs/test/layer-0-primitives/mail-srs.test.js +152 -0
  1082. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +279 -0
  1083. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +323 -0
  1084. package/lib/vendor/blamejs/test/layer-0-primitives/mail-unsubscribe.test.js +165 -0
  1085. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +439 -0
  1086. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-tool-registry.test.js +202 -0
  1087. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +155 -0
  1088. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-shadow-registry.test.js +112 -0
  1089. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +224 -0
  1090. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-compose-pipeline.test.js +278 -0
  1091. package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +376 -0
  1092. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-paths.test.js +89 -0
  1093. package/lib/vendor/blamejs/test/layer-0-primitives/nel.test.js +200 -0
  1094. package/lib/vendor/blamejs/test/layer-0-primitives/network-allowlist.test.js +106 -0
  1095. package/lib/vendor/blamejs/test/layer-0-primitives/network-byte-quota.test.js +133 -0
  1096. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +372 -0
  1097. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +635 -0
  1098. package/lib/vendor/blamejs/test/layer-0-primitives/network-heartbeat-passive.test.js +128 -0
  1099. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-build-options.test.js +130 -0
  1100. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls-ct-inclusion.test.js +179 -0
  1101. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +447 -0
  1102. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +369 -0
  1103. package/lib/vendor/blamejs/test/layer-0-primitives/nis2-report.test.js +21 -0
  1104. package/lib/vendor/blamejs/test/layer-0-primitives/nist-crosswalk.test.js +42 -0
  1105. package/lib/vendor/blamejs/test/layer-0-primitives/no-cache.test.js +98 -0
  1106. package/lib/vendor/blamejs/test/layer-0-primitives/notify.test.js +707 -0
  1107. package/lib/vendor/blamejs/test/layer-0-primitives/numeric-bounds.test.js +142 -0
  1108. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +72 -0
  1109. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +597 -0
  1110. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +190 -0
  1111. package/lib/vendor/blamejs/test/layer-0-primitives/openapi.test.js +877 -0
  1112. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +257 -0
  1113. package/lib/vendor/blamejs/test/layer-0-primitives/pagination.test.js +522 -0
  1114. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +216 -0
  1115. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +324 -0
  1116. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +546 -0
  1117. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +153 -0
  1118. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-software.test.js +94 -0
  1119. package/lib/vendor/blamejs/test/layer-0-primitives/problem-details.test.js +195 -0
  1120. package/lib/vendor/blamejs/test/layer-0-primitives/process-spawn.test.js +62 -0
  1121. package/lib/vendor/blamejs/test/layer-0-primitives/promise-pool.test.js +93 -0
  1122. package/lib/vendor/blamejs/test/layer-0-primitives/protected-resource-metadata.test.js +68 -0
  1123. package/lib/vendor/blamejs/test/layer-0-primitives/protobuf-encoder.test.js +138 -0
  1124. package/lib/vendor/blamejs/test/layer-0-primitives/protocol-dispatcher.test.js +174 -0
  1125. package/lib/vendor/blamejs/test/layer-0-primitives/public-suffix.test.js +197 -0
  1126. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +232 -0
  1127. package/lib/vendor/blamejs/test/layer-0-primitives/queue-dlq-extend-lease.test.js +178 -0
  1128. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +322 -0
  1129. package/lib/vendor/blamejs/test/layer-0-primitives/queue-priority-rate-progress.test.js +266 -0
  1130. package/lib/vendor/blamejs/test/layer-0-primitives/queue-sqs.test.js +300 -0
  1131. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-cluster.test.js +338 -0
  1132. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-registry.test.js +75 -0
  1133. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +246 -0
  1134. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +130 -0
  1135. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +335 -0
  1136. package/lib/vendor/blamejs/test/layer-0-primitives/request-log.test.js +170 -0
  1137. package/lib/vendor/blamejs/test/layer-0-primitives/require-auth-cache-control.test.js +93 -0
  1138. package/lib/vendor/blamejs/test/layer-0-primitives/require-mtls.test.js +34 -0
  1139. package/lib/vendor/blamejs/test/layer-0-primitives/resource-access-lock.test.js +52 -0
  1140. package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +67 -0
  1141. package/lib/vendor/blamejs/test/layer-0-primitives/retry.test.js +535 -0
  1142. package/lib/vendor/blamejs/test/layer-0-primitives/router-cross-origin-redirect.test.js +0 -0
  1143. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +128 -0
  1144. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +163 -0
  1145. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-parallel.test.js +170 -0
  1146. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +248 -0
  1147. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +451 -0
  1148. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +289 -0
  1149. package/lib/vendor/blamejs/test/layer-0-primitives/safe-icap.test.js +206 -0
  1150. package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +104 -0
  1151. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +339 -0
  1152. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mount-info.test.js +180 -0
  1153. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +78 -0
  1154. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sieve.test.js +123 -0
  1155. package/lib/vendor/blamejs/test/layer-0-primitives/safe-smtp.test.js +95 -0
  1156. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-idn-homograph.test.js +77 -0
  1157. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +257 -0
  1158. package/lib/vendor/blamejs/test/layer-0-primitives/saml-slo.test.js +249 -0
  1159. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +228 -0
  1160. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-exactly-once.test.js +238 -0
  1161. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +92 -0
  1162. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +700 -0
  1163. package/lib/vendor/blamejs/test/layer-0-primitives/sd-notify.test.js +67 -0
  1164. package/lib/vendor/blamejs/test/layer-0-primitives/sec-cyber.test.js +85 -0
  1165. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +107 -0
  1166. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +175 -0
  1167. package/lib/vendor/blamejs/test/layer-0-primitives/seeders.test.js +816 -0
  1168. package/lib/vendor/blamejs/test/layer-0-primitives/self-update-standalone-verifier.test.js +168 -0
  1169. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +302 -0
  1170. package/lib/vendor/blamejs/test/layer-0-primitives/server-timing.test.js +93 -0
  1171. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +247 -0
  1172. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +295 -0
  1173. package/lib/vendor/blamejs/test/layer-0-primitives/shape-match.test.js +142 -0
  1174. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +952 -0
  1175. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-multipart-sse.test.js +441 -0
  1176. package/lib/vendor/blamejs/test/layer-0-primitives/slug.test.js +330 -0
  1177. package/lib/vendor/blamejs/test/layer-0-primitives/smtp-policy.test.js +233 -0
  1178. package/lib/vendor/blamejs/test/layer-0-primitives/source-comment-blocks.test.js +105 -0
  1179. package/lib/vendor/blamejs/test/layer-0-primitives/speculation-rules.test.js +319 -0
  1180. package/lib/vendor/blamejs/test/layer-0-primitives/sse.test.js +148 -0
  1181. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +283 -0
  1182. package/lib/vendor/blamejs/test/layer-0-primitives/standard-webhooks.test.js +67 -0
  1183. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +266 -0
  1184. package/lib/vendor/blamejs/test/layer-0-primitives/step-up.test.js +487 -0
  1185. package/lib/vendor/blamejs/test/layer-0-primitives/storage-chunk-scratch.test.js +0 -0
  1186. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +773 -0
  1187. package/lib/vendor/blamejs/test/layer-0-primitives/stream-throttle.test.js +173 -0
  1188. package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +180 -0
  1189. package/lib/vendor/blamejs/test/layer-0-primitives/tcpa-10dlc.test.js +66 -0
  1190. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +89 -0
  1191. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +571 -0
  1192. package/lib/vendor/blamejs/test/layer-0-primitives/test-harness.test.js +190 -0
  1193. package/lib/vendor/blamejs/test/layer-0-primitives/testing-request.test.js +119 -0
  1194. package/lib/vendor/blamejs/test/layer-0-primitives/testing.test.js +522 -0
  1195. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +151 -0
  1196. package/lib/vendor/blamejs/test/layer-0-primitives/tls-exporter.test.js +168 -0
  1197. package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-ct.test.js +275 -0
  1198. package/lib/vendor/blamejs/test/layer-0-primitives/tls-ocsp-verify.test.js +105 -0
  1199. package/lib/vendor/blamejs/test/layer-0-primitives/tls-pinset-drift.test.js +35 -0
  1200. package/lib/vendor/blamejs/test/layer-0-primitives/tls-preferred-groups.test.js +81 -0
  1201. package/lib/vendor/blamejs/test/layer-0-primitives/tracing.test.js +280 -0
  1202. package/lib/vendor/blamejs/test/layer-0-primitives/uuid.test.js +93 -0
  1203. package/lib/vendor/blamejs/test/layer-0-primitives/vault-aad.test.js +277 -0
  1204. package/lib/vendor/blamejs/test/layer-0-primitives/vault-seal-pem-file.test.js +252 -0
  1205. package/lib/vendor/blamejs/test/layer-0-primitives/vendor-data.test.js +149 -0
  1206. package/lib/vendor/blamejs/test/layer-0-primitives/vendor-manifest.test.js +92 -0
  1207. package/lib/vendor/blamejs/test/layer-0-primitives/vex.test.js +661 -0
  1208. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +308 -0
  1209. package/lib/vendor/blamejs/test/layer-0-primitives/web-push-vapid.test.js +144 -0
  1210. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +674 -0
  1211. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-channels.test.js +360 -0
  1212. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool.test.js +302 -0
  1213. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +349 -0
  1214. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +717 -0
  1215. package/lib/vendor/blamejs/test/layer-5-integration/bundler-output.test.js +444 -0
  1216. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +597 -0
  1217. package/lib/vendor/blamejs/test/layer-5-integration/security-chaos.test.js +308 -0
  1218. package/lib/vendor/blamejs/test/smoke.js +431 -0
  1219. package/lib/webhooks.js +305 -0
  1220. package/package.json +43 -0
@@ -0,0 +1,2110 @@
1
+ "use strict";
2
+ /**
3
+ * Layer 3 — chain-writing modules (audit, consent, subject, checkpoint)
4
+ * + cluster-storage (SQL dispatcher).
5
+ *
6
+ * (Layer 3: uses db + chain-writer +
7
+ * cluster-storage). Hash-chained log tables and the framework write-path
8
+ * primitives that consume them.
9
+ *
10
+ * cluster-storage — SQL dispatcher (placeholderize, resolveTables,
11
+ * local + cluster dispatch)
12
+ * audit — chain append + verify + self-logging + begin-trace
13
+ * consent — chain append (uses chain-writer)
14
+ * subject — DSAR (export + delete) using audit + db
15
+ * append-only — INSERT-only trigger guards + foreign keys +
16
+ * table metadata reflection
17
+ * checkpoint — sign + verify + tamper detect + rollback detect
18
+ *
19
+ * Layers 0, 1, 2 must run first. Each test sets up its own tmpDir + db.
20
+ *
21
+ * Usage from smoke.js:
22
+ * var chainLayer = require("./30-chain");
23
+ * await chainLayer.run();
24
+ */
25
+
26
+ var helpers = require("./_helpers");
27
+ var b = helpers.b;
28
+ var fs = helpers.fs;
29
+ var os = helpers.os;
30
+ var path = helpers.path;
31
+ var check = helpers.check;
32
+ var setupTestDb = helpers.setupTestDb;
33
+ var teardownTestDb = helpers.teardownTestDb;
34
+ var setTestPassphraseEnv = helpers.setTestPassphraseEnv;
35
+ var _makeSqliteDriver = helpers._makeSqliteDriver;
36
+
37
+ async function testClusterStorageLocalDispatch() {
38
+ // With no cluster.init, executeAll should dispatch to local SQLite.
39
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cs-"));
40
+ try {
41
+ // Reset cluster BEFORE setupTestDb so its internal audit.checkpoint
42
+ // runs on the permanent-leader fallback (terminated=false).
43
+ b.cluster._resetForTest();
44
+ await setupTestDb(tmpDir);
45
+
46
+ // Seed an audit row via the existing local path so we have something
47
+ // to read back.
48
+ var ev = await b.audit.record({
49
+ actor: { kind: "user", id: "u1" },
50
+ action: "auth.login",
51
+ outcome: "success",
52
+ });
53
+ check("setup: audit row recorded locally", ev !== null);
54
+
55
+ // Now read back through cluster-storage. In single-node mode, should
56
+ // hit the local SQLite, table name is unprefixed.
57
+ check("tableName(audit_log) is unprefixed locally",
58
+ b.clusterStorage.tableName("audit_log") === "audit_log");
59
+
60
+ var rows = await b.clusterStorage.executeAll("SELECT _id, action FROM audit_log");
61
+ check("clusterStorage.executeAll local: row found", rows.length >= 1);
62
+ check("clusterStorage row has audit action", rows[0].action === "auth.login");
63
+ } finally {
64
+ await teardownTestDb(tmpDir);
65
+ }
66
+ }
67
+
68
+ function testClusterStoragePlaceholderize() {
69
+ check("placeholderize sqlite: passthrough",
70
+ b.clusterStorage.placeholderize("SELECT * FROM t WHERE a = ? AND b = ?", "sqlite") ===
71
+ "SELECT * FROM t WHERE a = ? AND b = ?");
72
+ check("placeholderize postgres: ? → $1, $2",
73
+ b.clusterStorage.placeholderize("SELECT * FROM t WHERE a = ? AND b = ?", "postgres") ===
74
+ "SELECT * FROM t WHERE a = $1 AND b = $2");
75
+ check("placeholderize: skips ? inside single-quoted strings",
76
+ b.clusterStorage.placeholderize("SELECT * FROM t WHERE label = '?' AND id = ?", "postgres") ===
77
+ "SELECT * FROM t WHERE label = '?' AND id = $1");
78
+ }
79
+
80
+ function testClusterStorageResolveTablesIsNoOpInSingleNode() {
81
+ b.cluster._resetForTest();
82
+ var sql = "SELECT * FROM audit_log";
83
+ check("resolveTables: passthrough when not cluster mode",
84
+ b.clusterStorage.resolveTables(sql) === sql);
85
+ }
86
+
87
+ async function testClusterStorageClusterDispatch() {
88
+ // Spin up a real cluster: full framework + external-db + cluster.init.
89
+ // Then run executeAll against external-db tables created by
90
+ // frameworkSchema.ensureSchema. The resolveTables should rewrite
91
+ // audit_log → _blamejs_audit_log automatically.
92
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cs-cluster-"));
93
+ var dbPath = path.join(tmpDir, "ext.db");
94
+ var driver = _makeSqliteDriver(dbPath);
95
+ try {
96
+ b.externalDb.init({
97
+ backends: {
98
+ "ops": { connect: driver.connect, query: driver.query, close: driver.close },
99
+ },
100
+ });
101
+ await b.frameworkSchema.ensureSchema({
102
+ externalDbBackend: "ops",
103
+ dialect: "sqlite",
104
+ });
105
+
106
+ b.cluster._resetForTest();
107
+ await b.cluster.init({
108
+ nodeId: "cs-cluster-test",
109
+ externalDbBackend: "ops",
110
+ dialect: "sqlite",
111
+ leaseTtl: b.constants.TIME.seconds(30),
112
+ heartbeatInterval: b.constants.TIME.seconds(10),
113
+ });
114
+
115
+ // Now in cluster mode. Insert a row using unprefixed name + ? placeholders.
116
+ await b.clusterStorage.execute(
117
+ "INSERT INTO audit_log (_id, recordedAt, monotonicCounter, action, outcome, prevHash, rowHash, nonce, fencingToken) " +
118
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
119
+ ["row1", Date.now(), 1, "auth.login", "success", "", "h1", Buffer.alloc(16), 1]
120
+ );
121
+
122
+ // Read back, also via unprefixed name. Dispatcher rewrites both.
123
+ var rows = await b.clusterStorage.executeAll("SELECT _id, action FROM audit_log WHERE _id = ?", ["row1"]);
124
+ check("clusterStorage cluster mode: row found via unprefixed name", rows.length === 1);
125
+ check("clusterStorage cluster mode: row data preserved", rows[0].action === "auth.login");
126
+
127
+ // Verify the row actually landed in the prefixed table
128
+ var directRows = await b.externalDb.query("SELECT _id FROM _blamejs_audit_log WHERE _id = ?", ["row1"]);
129
+ check("cluster row written to _blamejs_-prefixed external table", directRows.rows.length === 1);
130
+
131
+ // tableName getter reflects cluster mode
132
+ check("tableName(audit_log) prefixed in cluster mode",
133
+ b.clusterStorage.tableName("audit_log") === "_blamejs_audit_log");
134
+ } finally {
135
+ try { await b.cluster.shutdown(); } catch (_e) {}
136
+ try { await b.externalDb.shutdown(); } catch (_e) {}
137
+ driver._close();
138
+ fs.rmSync(tmpDir, { recursive: true, force: true });
139
+ }
140
+ }
141
+
142
+ // Single-node tests for the discovery surface — no external-db needed,
143
+ // run against the permanent-leader fallback.
144
+ function testClusterEndpointSingleNode() {
145
+ b.cluster._resetForTest();
146
+ check("cluster.endpoint() returns null in single-node fallback",
147
+ b.cluster.endpoint() === null);
148
+ }
149
+
150
+ async function testClusterDiscoveryHandlerSingleNode() {
151
+ b.cluster._resetForTest();
152
+ var handler = b.cluster.discoveryHandler();
153
+ check("cluster.discoveryHandler returns a function", typeof handler === "function");
154
+
155
+ // Mock res with capture
156
+ var captured = { status: null, headers: null, body: "" };
157
+ var res = {
158
+ writeHead: function (s, h) { captured.status = s; captured.headers = h; },
159
+ end: function (b) { captured.body += b || ""; },
160
+ };
161
+ await handler({ method: "GET", url: "/cluster/leader" }, res);
162
+
163
+ check("discoveryHandler: 200 in single-node fallback", captured.status === 200);
164
+ check("discoveryHandler: Content-Type is JSON",
165
+ captured.headers["Content-Type"].indexOf("application/json") === 0);
166
+ check("discoveryHandler: Cache-Control is no-store",
167
+ captured.headers["Cache-Control"] === "no-store");
168
+
169
+ var body = JSON.parse(captured.body);
170
+ check("discoveryHandler: leader.nodeId is single-node-local",
171
+ body.leader && body.leader.nodeId === "single-node-local");
172
+ check("discoveryHandler: leader.endpoint is null when unconfigured",
173
+ body.leader.endpoint === null);
174
+ check("discoveryHandler: self.isLeader is true in fallback",
175
+ body.self && body.self.isLeader === true);
176
+ }
177
+
178
+ async function testClusterEndpointInitValidation() {
179
+ b.cluster._resetForTest();
180
+
181
+ // Setup minimal external-db so cluster.init has somewhere to land —
182
+ // we'll never reach the heartbeat because validation throws first.
183
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-clep-"));
184
+ var dbPath = path.join(tmpDir, "ext.db");
185
+ var driver = _makeSqliteDriver(dbPath);
186
+ try {
187
+ b.externalDb.init({
188
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
189
+ });
190
+
191
+ // 1. http:// rejected by default (HTTPS-only allowlist)
192
+ var rejected = null;
193
+ try {
194
+ await b.cluster.init({
195
+ nodeId: "ep-test-1",
196
+ externalDbBackend: "ops",
197
+ dialect: "sqlite",
198
+ endpoint: "http://node1.internal:8080",
199
+ });
200
+ } catch (e) { rejected = e; }
201
+ check("cluster.init: http:// endpoint rejected by default",
202
+ rejected && rejected.code === "INVALID_ENDPOINT");
203
+ b.cluster._resetForTest();
204
+
205
+ // 2. Malformed URL rejected
206
+ var malformed = null;
207
+ try {
208
+ await b.cluster.init({
209
+ nodeId: "ep-test-2",
210
+ externalDbBackend: "ops",
211
+ dialect: "sqlite",
212
+ endpoint: "not-a-url",
213
+ });
214
+ } catch (e) { malformed = e; }
215
+ check("cluster.init: malformed endpoint rejected",
216
+ malformed && malformed.code === "INVALID_ENDPOINT");
217
+ b.cluster._resetForTest();
218
+
219
+ // 3. http:// accepted with explicit allowedProtocols opt-in
220
+ await b.cluster.init({
221
+ nodeId: "ep-test-3",
222
+ externalDbBackend: "ops",
223
+ dialect: "sqlite",
224
+ endpoint: "http://node1.internal:8080",
225
+ allowedProtocols: b.safeUrl.ALLOW_HTTP_ALL,
226
+ leaseTtl: b.constants.TIME.seconds(30),
227
+ heartbeatInterval: b.constants.TIME.seconds(10),
228
+ });
229
+ check("cluster.endpoint() returns configured value",
230
+ b.cluster.endpoint() === "http://node1.internal:8080");
231
+ } finally {
232
+ try { await b.cluster.shutdown(); } catch (_e) {}
233
+ try { await b.externalDb.shutdown(); } catch (_e) {}
234
+ driver._close();
235
+ fs.rmSync(tmpDir, { recursive: true, force: true });
236
+ }
237
+ }
238
+
239
+ async function testClusterDiscoveryAcquiredLeader() {
240
+ // Spin up a real cluster, configure an endpoint, verify the leader-row
241
+ // captures it AND discoveryHandler reports it back.
242
+ b.cluster._resetForTest();
243
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-disc-"));
244
+ var dbPath = path.join(tmpDir, "ext.db");
245
+ var driver = _makeSqliteDriver(dbPath);
246
+ try {
247
+ b.externalDb.init({
248
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
249
+ });
250
+ await b.frameworkSchema.ensureSchema({
251
+ externalDbBackend: "ops",
252
+ dialect: "sqlite",
253
+ });
254
+
255
+ await b.cluster.init({
256
+ nodeId: "disc-test-1",
257
+ externalDbBackend: "ops",
258
+ dialect: "sqlite",
259
+ endpoint: "https://disc-test-1.internal:8443",
260
+ leaseTtl: b.constants.TIME.seconds(30),
261
+ heartbeatInterval: b.constants.TIME.seconds(10),
262
+ });
263
+
264
+ check("cluster.isLeader after acquire", b.cluster.isLeader() === true);
265
+
266
+ var leader = await b.cluster.currentLeader();
267
+ check("currentLeader: nodeId matches",
268
+ leader && leader.nodeId === "disc-test-1");
269
+ check("currentLeader: endpoint persisted to leader row",
270
+ leader.endpoint === "https://disc-test-1.internal:8443");
271
+ check("currentLeader: fencingToken is monotonic (>= 1)",
272
+ typeof leader.fencingToken === "number" && leader.fencingToken >= 1);
273
+
274
+ // discoveryHandler reports leader + endpoint
275
+ var captured = { status: null, body: "" };
276
+ var res = {
277
+ writeHead: function (s, _h) { captured.status = s; },
278
+ end: function (b) { captured.body += b || ""; },
279
+ };
280
+ await b.cluster.discoveryHandler()({ method: "GET" }, res);
281
+ check("discoveryHandler: 200 with active leader", captured.status === 200);
282
+ var body = JSON.parse(captured.body);
283
+ check("discoveryHandler: leader.nodeId in cluster mode",
284
+ body.leader.nodeId === "disc-test-1");
285
+ check("discoveryHandler: leader.endpoint in cluster mode",
286
+ body.leader.endpoint === "https://disc-test-1.internal:8443");
287
+ check("discoveryHandler: self.isLeader is true", body.self.isLeader === true);
288
+ check("discoveryHandler: self.endpoint matches",
289
+ body.self.endpoint === "https://disc-test-1.internal:8443");
290
+ } finally {
291
+ try { await b.cluster.shutdown(); } catch (_e) {}
292
+ try { await b.externalDb.shutdown(); } catch (_e) {}
293
+ driver._close();
294
+ fs.rmSync(tmpDir, { recursive: true, force: true });
295
+ }
296
+ }
297
+
298
+ async function testClusterAuditTipFencing() {
299
+ // Verify the canonical fencing-token guard on _blamejs_audit_tip:
300
+ // 1. First write (fencingToken=N) — INSERT path, accepted
301
+ // 2. Same-token re-write (N) — UPDATE path with WHERE N <= N, accepted
302
+ // 3. Higher-token write (N+5) — UPDATE path, accepted
303
+ // 4. Lower-token write (N+2) — UPDATE rejected by WHERE clause,
304
+ // audit.checkpoint() throws ClusterError(code=FENCED_OUT).
305
+ //
306
+ // We drive checkpoint() directly rather than recreating the DB row by
307
+ // hand — this proves the framework's actual write path enforces the
308
+ // fence, not just that the SQL would do the right thing in isolation.
309
+ //
310
+ // Forcing the leader's fencingToken to step down is non-trivial in a
311
+ // single-process test (the cluster module's lease state isn't directly
312
+ // mutable). Instead we drive _upsertAuditTip directly with explicit
313
+ // tokens — that's the function the framework's write path calls, and
314
+ // it carries the WHERE-clause guard.
315
+ b.cluster._resetForTest();
316
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-fence-"));
317
+ var dbPath = path.join(tmpDir, "ext.db");
318
+ var driver = _makeSqliteDriver(dbPath);
319
+ try {
320
+ b.externalDb.init({
321
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
322
+ });
323
+ await b.frameworkSchema.ensureSchema({
324
+ externalDbBackend: "ops",
325
+ dialect: "sqlite",
326
+ });
327
+
328
+ await b.cluster.init({
329
+ nodeId: "fence-test-1",
330
+ externalDbBackend: "ops",
331
+ dialect: "sqlite",
332
+ leaseTtl: b.constants.TIME.seconds(30),
333
+ heartbeatInterval: b.constants.TIME.seconds(10),
334
+ });
335
+
336
+ // Direct upserts via cluster-storage (bypasses audit.checkpoint's
337
+ // chain-tip read so we can test the fence in isolation).
338
+ async function upsert(counter, hash, signedAt, token) {
339
+ var result = await b.clusterStorage.execute(
340
+ "INSERT INTO _blamejs_audit_tip " +
341
+ " (scope, atMonotonicCounter, rowHash, signedAt, fencingToken) " +
342
+ "VALUES ('audit', ?, ?, ?, ?) " +
343
+ "ON CONFLICT (scope) DO UPDATE SET " +
344
+ " atMonotonicCounter = EXCLUDED.atMonotonicCounter, " +
345
+ " rowHash = EXCLUDED.rowHash, " +
346
+ " signedAt = EXCLUDED.signedAt, " +
347
+ " fencingToken = EXCLUDED.fencingToken " +
348
+ "WHERE _blamejs_audit_tip.fencingToken <= EXCLUDED.fencingToken " +
349
+ "RETURNING fencingToken",
350
+ [counter, hash, signedAt, token]
351
+ );
352
+ return result.rows.length > 0;
353
+ }
354
+
355
+ // 1. First write (token=3) succeeds — INSERT path
356
+ check("audit-tip: first write at token=3 accepted",
357
+ (await upsert(1, "h1", "1", 3)) === true);
358
+
359
+ // 2. Same-token rewrite (token=3) — WHERE 3<=3 → UPDATE path
360
+ check("audit-tip: same-token rewrite at token=3 accepted",
361
+ (await upsert(2, "h2", "2", 3)) === true);
362
+
363
+ // 3. Higher-token bump (token=8) — WHERE 3<=8 → UPDATE
364
+ check("audit-tip: higher-token write at token=8 accepted",
365
+ (await upsert(3, "h3", "3", 8)) === true);
366
+
367
+ // 4. Stale-token write (token=5, stored=8) — fenced out
368
+ check("audit-tip: lower-token write at token=5 rejected (fenced)",
369
+ (await upsert(4, "h4", "4", 5)) === false);
370
+
371
+ // The stored row should still reflect the highest-accepted token (8)
372
+ var stored = await b.clusterStorage.executeOne(
373
+ "SELECT fencingToken, rowHash FROM _blamejs_audit_tip WHERE scope = 'audit'"
374
+ );
375
+ check("audit-tip: stored token unchanged after rejected write",
376
+ Number(stored.fencingToken) === 8);
377
+ check("audit-tip: stored rowHash unchanged after rejected write",
378
+ stored.rowHash === "h3");
379
+ } finally {
380
+ try { await b.cluster.shutdown(); } catch (_e) {}
381
+ try { await b.externalDb.shutdown(); } catch (_e) {}
382
+ driver._close();
383
+ fs.rmSync(tmpDir, { recursive: true, force: true });
384
+ }
385
+ }
386
+
387
+ async function testClusterSessionsSharedAcrossNodes() {
388
+ // Sessions migrated to external-db when migrated to external-db — a session created on
389
+ // the leader must be verifiable by reading the SAME external-db row.
390
+ // We can't truly stand up two node processes in-test, so we simulate
391
+ // the cluster-shared-storage property by:
392
+ // 1. cluster.init as leader, create a session — row lands in
393
+ // external-db's _blamejs_sessions.
394
+ // 2. SELECT directly from external-db; row is there with sealed
395
+ // data (proves it didn't go to local SQLite).
396
+ // 3. session.verify reads through cluster-storage and returns
397
+ // the unsealed row — proves the round-trip works.
398
+ // 4. Compare against the local SQLite _blamejs_sessions table —
399
+ // should be empty (proves cluster mode is actually routing
400
+ // reads/writes away from local).
401
+ b.cluster._resetForTest();
402
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-sess-cl-"));
403
+ var dbPath = path.join(tmpDir, "ext.db");
404
+ var driver = _makeSqliteDriver(dbPath);
405
+ try {
406
+ await setupTestDb(tmpDir);
407
+ b.externalDb.init({
408
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
409
+ });
410
+ await b.frameworkSchema.ensureSchema({
411
+ externalDbBackend: "ops",
412
+ dialect: "sqlite",
413
+ });
414
+ await b.cluster.init({
415
+ nodeId: "sess-cluster-1",
416
+ externalDbBackend: "ops",
417
+ dialect: "sqlite",
418
+ leaseTtl: b.constants.TIME.seconds(30),
419
+ heartbeatInterval: b.constants.TIME.seconds(10),
420
+ });
421
+
422
+ var s = await b.session.create({ userId: "u-cluster-1", data: { role: "admin" } });
423
+ check("create returned token", typeof s.token === "string");
424
+
425
+ // Row lands in external-db, NOT in local SQLite
426
+ var extRows = await b.externalDb.query(
427
+ "SELECT sidHash FROM _blamejs_sessions",
428
+ [], { backend: "ops" }
429
+ );
430
+ check("session row in external-db", extRows.rows.length === 1);
431
+ check("session row sidHash is hashed (128 hex)",
432
+ /^[0-9a-f]{128}$/.test(extRows.rows[0].sidHash));
433
+
434
+ var localRows = b.db.prepare("SELECT sidHash FROM _blamejs_sessions").all();
435
+ check("local SQLite session table is empty in cluster mode",
436
+ localRows.length === 0);
437
+
438
+ // Round-trip: verify reads back through external-db
439
+ var v = await b.session.verify(s.token);
440
+ check("cluster-mode verify returns userId", v && v.userId === "u-cluster-1");
441
+ check("cluster-mode verify returns unsealed data",
442
+ v && v.data && v.data.role === "admin");
443
+
444
+ // Cleanup via destroy hits external-db too
445
+ var destroyed = await b.session.destroy(s.token);
446
+ check("cluster-mode destroy returns true", destroyed === true);
447
+ var afterDelete = await b.externalDb.query(
448
+ "SELECT COUNT(*) AS n FROM _blamejs_sessions",
449
+ [], { backend: "ops" }
450
+ );
451
+ check("session row removed from external-db", Number(afterDelete.rows[0].n) === 0);
452
+ } finally {
453
+ try { await b.cluster.shutdown(); } catch (_e) {}
454
+ try { await b.externalDb.shutdown(); } catch (_e) {}
455
+ driver._close();
456
+ await teardownTestDb(tmpDir);
457
+ }
458
+ }
459
+
460
+ async function testClusterConsentTipFencing() {
461
+ // Mirror of testClusterAuditTipFencing but for the consent chain:
462
+ // verify the canonical fencing-token guard on _blamejs_consent_tip
463
+ // through direct upserts (3, 3, 8, 5 token sequence).
464
+ b.cluster._resetForTest();
465
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cf-"));
466
+ var dbPath = path.join(tmpDir, "ext.db");
467
+ var driver = _makeSqliteDriver(dbPath);
468
+ try {
469
+ b.externalDb.init({
470
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
471
+ });
472
+ await b.frameworkSchema.ensureSchema({
473
+ externalDbBackend: "ops",
474
+ dialect: "sqlite",
475
+ });
476
+ await b.cluster.init({
477
+ nodeId: "consent-fence-1",
478
+ externalDbBackend: "ops",
479
+ dialect: "sqlite",
480
+ leaseTtl: b.constants.TIME.seconds(30),
481
+ heartbeatInterval: b.constants.TIME.seconds(10),
482
+ });
483
+
484
+ async function upsert(counter, hash, signedAt, token) {
485
+ var result = await b.clusterStorage.execute(
486
+ "INSERT INTO _blamejs_consent_tip " +
487
+ " (scope, atMonotonicCounter, rowHash, signedAt, fencingToken) " +
488
+ "VALUES ('consent', ?, ?, ?, ?) " +
489
+ "ON CONFLICT (scope) DO UPDATE SET " +
490
+ " atMonotonicCounter = EXCLUDED.atMonotonicCounter, " +
491
+ " rowHash = EXCLUDED.rowHash, " +
492
+ " signedAt = EXCLUDED.signedAt, " +
493
+ " fencingToken = EXCLUDED.fencingToken " +
494
+ "WHERE _blamejs_consent_tip.fencingToken <= EXCLUDED.fencingToken " +
495
+ "RETURNING fencingToken",
496
+ [counter, hash, signedAt, token]
497
+ );
498
+ return result.rows.length > 0;
499
+ }
500
+
501
+ check("consent-tip: first write at token=3 accepted",
502
+ (await upsert(1, "h1", "1", 3)) === true);
503
+ check("consent-tip: same-token rewrite at token=3 accepted",
504
+ (await upsert(2, "h2", "2", 3)) === true);
505
+ check("consent-tip: higher-token write at token=8 accepted",
506
+ (await upsert(3, "h3", "3", 8)) === true);
507
+ check("consent-tip: lower-token write at token=5 rejected (fenced)",
508
+ (await upsert(4, "h4", "4", 5)) === false);
509
+
510
+ var stored = await b.clusterStorage.executeOne(
511
+ "SELECT fencingToken, rowHash FROM _blamejs_consent_tip WHERE scope = 'consent'"
512
+ );
513
+ check("consent-tip: stored token unchanged after rejected write",
514
+ Number(stored.fencingToken) === 8);
515
+ check("consent-tip: stored rowHash unchanged after rejected write",
516
+ stored.rowHash === "h3");
517
+ } finally {
518
+ try { await b.cluster.shutdown(); } catch (_e) {}
519
+ try { await b.externalDb.shutdown(); } catch (_e) {}
520
+ driver._close();
521
+ fs.rmSync(tmpDir, { recursive: true, force: true });
522
+ }
523
+ }
524
+
525
+ async function testClusterConsentTipUpdatedOnGrant() {
526
+ // The actual integration: consent.grant in cluster mode writes the
527
+ // chain row AND upserts _blamejs_consent_tip. After a grant, the
528
+ // tip should record the row's monotonicCounter and rowHash.
529
+ b.cluster._resetForTest();
530
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-ct-grant-"));
531
+ var dbPath = path.join(tmpDir, "ext.db");
532
+ var driver = _makeSqliteDriver(dbPath);
533
+ try {
534
+ await setupTestDb(tmpDir);
535
+ b.externalDb.init({
536
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
537
+ });
538
+ await b.frameworkSchema.ensureSchema({
539
+ externalDbBackend: "ops",
540
+ dialect: "sqlite",
541
+ });
542
+ await b.cluster.init({
543
+ nodeId: "consent-grant-1",
544
+ externalDbBackend: "ops",
545
+ dialect: "sqlite",
546
+ leaseTtl: b.constants.TIME.seconds(30),
547
+ heartbeatInterval: b.constants.TIME.seconds(10),
548
+ });
549
+
550
+ var grantResult = await b.consent.grant({
551
+ subjectId: "subj-1",
552
+ purpose: "marketing.email",
553
+ lawfulBasis: "consent",
554
+ channel: "ui",
555
+ });
556
+ check("consent.grant returned a row with monotonicCounter",
557
+ grantResult && typeof grantResult.monotonicCounter === "number");
558
+
559
+ // Consent tip should now reflect the grant
560
+ var tip = await b.externalDb.query(
561
+ "SELECT atMonotonicCounter, rowHash FROM _blamejs_consent_tip WHERE scope='consent'",
562
+ [], { backend: "ops" }
563
+ );
564
+ check("consent-tip: row exists after first grant",
565
+ tip.rows.length === 1);
566
+ check("consent-tip: counter matches grant's monotonicCounter",
567
+ Number(tip.rows[0].atMonotonicCounter) === Number(grantResult.monotonicCounter));
568
+ check("consent-tip: rowHash matches grant's rowHash",
569
+ tip.rows[0].rowHash === grantResult.rowHash);
570
+
571
+ // Second grant advances the tip
572
+ var grant2 = await b.consent.grant({
573
+ subjectId: "subj-2",
574
+ purpose: "marketing.email",
575
+ lawfulBasis: "consent",
576
+ channel: "ui",
577
+ });
578
+ var tip2 = await b.externalDb.query(
579
+ "SELECT atMonotonicCounter, rowHash FROM _blamejs_consent_tip WHERE scope='consent'",
580
+ [], { backend: "ops" }
581
+ );
582
+ check("consent-tip: counter advanced on second grant",
583
+ Number(tip2.rows[0].atMonotonicCounter) === Number(grant2.monotonicCounter));
584
+ } finally {
585
+ try { await b.cluster.shutdown(); } catch (_e) {}
586
+ try { await b.externalDb.shutdown(); } catch (_e) {}
587
+ driver._close();
588
+ await teardownTestDb(tmpDir);
589
+ }
590
+ }
591
+
592
+ async function testClusterConsentRollbackDetected() {
593
+ // Pre-seed consent-tip with counter=999 + empty consent_log; spawn
594
+ // a child that runs cluster.init and verify it exits 1 with the
595
+ // generalized "consent-log rollback detected" message.
596
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cr-detect-"));
597
+ var dbPath = path.join(tmpDir, "ext.db");
598
+ var driver = _makeSqliteDriver(dbPath);
599
+ try {
600
+ b.externalDb.init({
601
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
602
+ });
603
+ await b.frameworkSchema.ensureSchema({
604
+ externalDbBackend: "ops",
605
+ dialect: "sqlite",
606
+ });
607
+ await b.externalDb.query(
608
+ "INSERT INTO _blamejs_consent_tip (scope, atMonotonicCounter, rowHash, signedAt, fencingToken) " +
609
+ "VALUES ('consent', 999, 'rolled-hash', '0', 5)"
610
+ );
611
+ await b.externalDb.shutdown();
612
+ driver._close();
613
+
614
+ var spawnSync = require("child_process").spawnSync;
615
+ var indexPath = path.resolve(__dirname, "..", "index.js").replace(/\\/g, "/");
616
+ var dbPathForChild = dbPath.replace(/\\/g, "/");
617
+ var childScript =
618
+ "var b = require('" + indexPath + "');\n" +
619
+ "var sqlite = require('node:sqlite');\n" +
620
+ "var conn = new sqlite.DatabaseSync('" + dbPathForChild + "');\n" +
621
+ "var driver = {\n" +
622
+ " connect: async function () { return { id: 'c1' }; },\n" +
623
+ " query: async function (_c, sql, params) {\n" +
624
+ " var stmt = conn.prepare(sql);\n" +
625
+ " if (/^\\s*SELECT/i.test(sql) || /\\bRETURNING\\b/i.test(sql)) {\n" +
626
+ " return { rows: stmt.all.apply(stmt, params || []), rowCount: 0 };\n" +
627
+ " }\n" +
628
+ " var info = stmt.run.apply(stmt, params || []);\n" +
629
+ " return { rows: [], rowCount: info.changes };\n" +
630
+ " },\n" +
631
+ " close: async function () {},\n" +
632
+ "};\n" +
633
+ "(async function () {\n" +
634
+ " b.externalDb.init({ backends: { ops: driver } });\n" +
635
+ " await b.cluster.init({ nodeId: 'cr-child', externalDbBackend: 'ops', dialect: 'sqlite', leaseTtl: 30000, heartbeatInterval: 10000 });\n" +
636
+ " console.log('UNEXPECTED-BOOT');\n" +
637
+ "})().catch(function (e) { console.error('CHILD-ERR ' + e.message); process.exit(99); });\n";
638
+ var result = spawnSync(process.execPath, ["-e", childScript], { encoding: "utf8" });
639
+ check("consent-rollback boot exits via the catch handler (code 99)",
640
+ result.status === 99);
641
+ check("consent-rollback boot logs the consent-chain message",
642
+ /consent-log rollback detected/i.test(result.stderr || ""));
643
+ } finally {
644
+ fs.rmSync(tmpDir, { recursive: true, force: true });
645
+ }
646
+ }
647
+
648
+ async function testClusterQueueJobsSharedAcrossNodes() {
649
+ // Queue jobs migrated to external-db when migrated to external-db — enqueue from the
650
+ // leader writes to external-db; lease + complete observe the same
651
+ // shared row. Mirrors the session-cluster test's structure: one
652
+ // node process, but verifies storage-routing properties.
653
+ b.cluster._resetForTest();
654
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-q-cl-"));
655
+ var dbPath = path.join(tmpDir, "ext.db");
656
+ var driver = _makeSqliteDriver(dbPath);
657
+ try {
658
+ await setupTestDb(tmpDir);
659
+ b.externalDb.init({
660
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
661
+ });
662
+ await b.frameworkSchema.ensureSchema({
663
+ externalDbBackend: "ops",
664
+ dialect: "sqlite",
665
+ });
666
+ await b.cluster.init({
667
+ nodeId: "q-cluster-1",
668
+ externalDbBackend: "ops",
669
+ dialect: "sqlite",
670
+ leaseTtl: b.constants.TIME.seconds(30),
671
+ heartbeatInterval: b.constants.TIME.seconds(10),
672
+ });
673
+
674
+ // Use the queue-local protocol directly so the test focuses on the
675
+ // storage-routing semantics, not the dispatcher's audit-emit /
676
+ // breaker layers (those have their own tests).
677
+ var queueLocal = require("../lib/queue-local").create();
678
+ var enq = await queueLocal.enqueue("cl-test", { x: 42 }, { traceId: "trace-1" });
679
+ check("cluster queue: enqueue returns jobId", typeof enq.jobId === "string");
680
+
681
+ // Row lands in external-db, NOT in local SQLite
682
+ var extRows = await b.externalDb.query(
683
+ "SELECT _id, queueName, status FROM _blamejs_jobs",
684
+ [], { backend: "ops" }
685
+ );
686
+ check("cluster queue: row in external-db", extRows.rows.length === 1);
687
+ check("cluster queue: row status is pending", extRows.rows[0].status === "pending");
688
+
689
+ var localRows = b.db.prepare("SELECT _id FROM _blamejs_jobs").all();
690
+ check("cluster queue: local SQLite jobs table empty",
691
+ localRows.length === 0);
692
+
693
+ // Lease via the same external-db storage; payload round-trips
694
+ // through the seal/unseal pipeline correctly
695
+ var leased = await queueLocal.lease("cl-test", b.constants.TIME.seconds(30), 1);
696
+ check("cluster queue: lease returns 1 job", leased.length === 1);
697
+ check("cluster queue: lease unseals payload",
698
+ leased[0].payload && leased[0].payload.x === 42);
699
+ check("cluster queue: lease preserves traceId", leased[0].traceId === "trace-1");
700
+
701
+ // Status transition lands in external-db
702
+ var afterLease = await b.externalDb.query(
703
+ "SELECT status, attempts FROM _blamejs_jobs WHERE _id = ?",
704
+ [enq.jobId], { backend: "ops" }
705
+ );
706
+ check("cluster queue: row status flipped to inflight",
707
+ afterLease.rows[0].status === "inflight");
708
+ check("cluster queue: attempts incremented",
709
+ Number(afterLease.rows[0].attempts) === 1);
710
+
711
+ // Complete cycles back to external-db
712
+ var done = await queueLocal.complete(enq.jobId);
713
+ check("cluster queue: complete returns true", done === true);
714
+ var afterDone = await b.externalDb.query(
715
+ "SELECT status FROM _blamejs_jobs WHERE _id = ?",
716
+ [enq.jobId], { backend: "ops" }
717
+ );
718
+ check("cluster queue: row status now done", afterDone.rows[0].status === "done");
719
+ } finally {
720
+ try { await b.cluster.shutdown(); } catch (_e) {}
721
+ try { await b.externalDb.shutdown(); } catch (_e) {}
722
+ driver._close();
723
+ await teardownTestDb(tmpDir);
724
+ }
725
+ }
726
+
727
+ async function testClusterVaultKeyFirstBootRecords() {
728
+ // First cluster boot: no _blamejs_cluster_state row yet. cluster.init
729
+ // should write THIS node's vault-key fingerprint and record nodeId.
730
+ // Subsequent cluster.init from the same vault file passes without
731
+ // changes (idempotent).
732
+ b.cluster._resetForTest();
733
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-vk-first-"));
734
+ var dbPath = path.join(tmpDir, "ext.db");
735
+ var driver = _makeSqliteDriver(dbPath);
736
+ try {
737
+ await setupTestDb(tmpDir); // initializes vault
738
+ b.externalDb.init({
739
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
740
+ });
741
+ await b.frameworkSchema.ensureSchema({
742
+ externalDbBackend: "ops",
743
+ dialect: "sqlite",
744
+ });
745
+
746
+ // First boot — writes the row.
747
+ await b.cluster.init({
748
+ nodeId: "vk-first-1",
749
+ externalDbBackend: "ops",
750
+ dialect: "sqlite",
751
+ leaseTtl: b.constants.TIME.seconds(30),
752
+ heartbeatInterval: b.constants.TIME.seconds(10),
753
+ });
754
+ var stored = await b.externalDb.query(
755
+ "SELECT vaultKeyFp, recordedByNode FROM _blamejs_cluster_state WHERE scope='state'",
756
+ [], { backend: "ops" }
757
+ );
758
+ check("cluster-state row recorded after first boot",
759
+ stored.rows.length === 1);
760
+ check("cluster-state recorded by this node",
761
+ stored.rows[0].recordedByNode === "vk-first-1");
762
+ check("cluster-state fingerprint is hex sha3-512 (128 chars)",
763
+ /^[0-9a-f]{128}$/.test(stored.rows[0].vaultKeyFp));
764
+
765
+ // Same vault, fresh cluster.init — passes silently
766
+ await b.cluster.shutdown();
767
+ await b.cluster.init({
768
+ nodeId: "vk-first-2",
769
+ externalDbBackend: "ops",
770
+ dialect: "sqlite",
771
+ leaseTtl: b.constants.TIME.seconds(30),
772
+ heartbeatInterval: b.constants.TIME.seconds(10),
773
+ });
774
+ var stored2 = await b.externalDb.query(
775
+ "SELECT vaultKeyFp, recordedByNode FROM _blamejs_cluster_state WHERE scope='state'",
776
+ [], { backend: "ops" }
777
+ );
778
+ check("cluster-state fingerprint unchanged after same-vault re-init",
779
+ stored2.rows[0].vaultKeyFp === stored.rows[0].vaultKeyFp);
780
+ check("cluster-state recordedByNode unchanged (first writer wins)",
781
+ stored2.rows[0].recordedByNode === "vk-first-1");
782
+ } finally {
783
+ try { await b.cluster.shutdown(); } catch (_e) {}
784
+ try { await b.externalDb.shutdown(); } catch (_e) {}
785
+ driver._close();
786
+ await teardownTestDb(tmpDir);
787
+ }
788
+ }
789
+
790
+ async function testClusterVaultKeyMismatchDetected() {
791
+ // Pre-seed the cluster-state row with a fingerprint that won't match
792
+ // the freshly-generated vault keys in the child process. cluster.init
793
+ // detects the drift and process.exit(1)s. Spawn-a-child pattern so
794
+ // we can capture the exit code.
795
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-vk-drift-"));
796
+ var dbPath = path.join(tmpDir, "ext.db");
797
+ var driver = _makeSqliteDriver(dbPath);
798
+ try {
799
+ b.externalDb.init({
800
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
801
+ });
802
+ // Provider ensureSchema creates _blamejs_leader + _blamejs_cluster_state.
803
+ // We don't run cluster.init here — just construct the provider manually
804
+ // so the table exists, then pre-seed with a wrong fingerprint.
805
+ var providerDb = require("../lib/cluster-provider-db");
806
+ var prov = providerDb.create({ externalDbBackend: "ops", dialect: "sqlite" });
807
+ await prov.ensureSchema();
808
+
809
+ await b.externalDb.query(
810
+ "INSERT INTO _blamejs_cluster_state (scope, vaultKeyFp, recordedAt, recordedByNode) " +
811
+ "VALUES ('state', ?, ?, 'pre-existing-node')",
812
+ ["deadbeef".repeat(16), Date.now()] // 128-hex bogus fingerprint
813
+ );
814
+ await b.externalDb.shutdown();
815
+ driver._close();
816
+
817
+ var spawnSync = require("child_process").spawnSync;
818
+ var indexPath = path.resolve(__dirname, "..", "index.js").replace(/\\/g, "/");
819
+ var dbPathForChild = dbPath.replace(/\\/g, "/");
820
+ var childTmp = path.resolve(tmpDir, "child-data").replace(/\\/g, "/");
821
+ var childScript =
822
+ "var b = require('" + indexPath + "');\n" +
823
+ "var sqlite = require('node:sqlite');\n" +
824
+ "var conn = new sqlite.DatabaseSync('" + dbPathForChild + "');\n" +
825
+ "var driver = {\n" +
826
+ " connect: async function () { return { id: 'c1' }; },\n" +
827
+ " query: async function (_c, sql, params) {\n" +
828
+ " var stmt = conn.prepare(sql);\n" +
829
+ " if (/^\\s*SELECT/i.test(sql) || /\\bRETURNING\\b/i.test(sql)) {\n" +
830
+ " return { rows: stmt.all.apply(stmt, params || []), rowCount: 0 };\n" +
831
+ " }\n" +
832
+ " var info = stmt.run.apply(stmt, params || []);\n" +
833
+ " return { rows: [], rowCount: info.changes };\n" +
834
+ " },\n" +
835
+ " close: async function () {},\n" +
836
+ "};\n" +
837
+ "process.env.BLAMEJS_SKIP_NTP_CHECK = '1';\n" +
838
+ "(async function () {\n" +
839
+ " require('fs').mkdirSync('" + childTmp + "', { recursive: true });\n" +
840
+ " await b.vault.init({ dataDir: '" + childTmp + "', mode: 'plaintext' });\n" +
841
+ " b.externalDb.init({ backends: { ops: driver } });\n" +
842
+ " await b.cluster.init({ nodeId: 'vk-drift-child', externalDbBackend: 'ops', dialect: 'sqlite', leaseTtl: 30000, heartbeatInterval: 10000 });\n" +
843
+ " console.log('UNEXPECTED-BOOT');\n" +
844
+ "})().catch(function (e) { console.error('CHILD-ERR ' + e.message); process.exit(99); });\n";
845
+ var result = spawnSync(process.execPath, ["-e", childScript], { encoding: "utf8" });
846
+ check("vault-key drift boot exits via the catch handler (code 99)",
847
+ result.status === 99);
848
+ check("vault-key drift boot logs detection message",
849
+ /vault-key drift detected/i.test(result.stderr || ""));
850
+ check("vault-key drift boot did NOT print UNEXPECTED-BOOT",
851
+ (result.stdout || "").indexOf("UNEXPECTED-BOOT") === -1);
852
+ } finally {
853
+ fs.rmSync(tmpDir, { recursive: true, force: true });
854
+ }
855
+ }
856
+
857
+ async function testClusterAuditTipRollbackHappyPath() {
858
+ // Happy path — tip matches the row at its recorded counter, cluster.init
859
+ // proceeds. Pre-populate an audit_log row + a matching tip row, then
860
+ // run cluster.init; verify the rollback-check log line and a clean
861
+ // boot.
862
+ b.cluster._resetForTest();
863
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-rb-ok-"));
864
+ var dbPath = path.join(tmpDir, "ext.db");
865
+ var driver = _makeSqliteDriver(dbPath);
866
+ try {
867
+ b.externalDb.init({
868
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
869
+ });
870
+ await b.frameworkSchema.ensureSchema({
871
+ externalDbBackend: "ops",
872
+ dialect: "sqlite",
873
+ });
874
+ // One audit_log row at counter=1 with hash "h1", plus a tip row
875
+ // pointing at it. cluster.init should accept this as a clean state.
876
+ await b.externalDb.query(
877
+ "INSERT INTO _blamejs_audit_log " +
878
+ "(_id, recordedAt, monotonicCounter, action, outcome, prevHash, rowHash, nonce, fencingToken) " +
879
+ "VALUES ('row-ok', ?, 1, 'system.test.ok', 'success', '', 'h1', x'00000000000000000000000000000000', 1)",
880
+ [Date.now()]
881
+ );
882
+ await b.externalDb.query(
883
+ "INSERT INTO _blamejs_audit_tip (scope, atMonotonicCounter, rowHash, signedAt, fencingToken) " +
884
+ "VALUES ('audit', 1, 'h1', '0', 1)"
885
+ );
886
+
887
+ var threw = null;
888
+ try {
889
+ await b.cluster.init({
890
+ nodeId: "rb-ok-1",
891
+ externalDbBackend: "ops",
892
+ dialect: "sqlite",
893
+ leaseTtl: b.constants.TIME.seconds(30),
894
+ heartbeatInterval: b.constants.TIME.seconds(10),
895
+ });
896
+ } catch (e) { threw = e; }
897
+ check("cluster.init: happy-path rollback check passes", threw === null);
898
+ check("cluster.init: lease acquired", b.cluster.isLeader() === true);
899
+ } finally {
900
+ try { await b.cluster.shutdown(); } catch (_e) {}
901
+ try { await b.externalDb.shutdown(); } catch (_e) {}
902
+ driver._close();
903
+ fs.rmSync(tmpDir, { recursive: true, force: true });
904
+ }
905
+ }
906
+
907
+ async function testClusterAuditTipRollbackDetected() {
908
+ // Pre-seed a tip recording counter=999 with no matching audit_log
909
+ // row. cluster.init should detect this as rollback (current MAX <
910
+ // tip counter) and process.exit(1). We fork a child process to
911
+ // capture the exit code and stderr — same pattern as the
912
+ // single-node testRollbackDetection.
913
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-rb-detect-"));
914
+ var dbPath = path.join(tmpDir, "ext.db");
915
+ var driver = _makeSqliteDriver(dbPath);
916
+ try {
917
+ b.externalDb.init({
918
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
919
+ });
920
+ await b.frameworkSchema.ensureSchema({
921
+ externalDbBackend: "ops",
922
+ dialect: "sqlite",
923
+ });
924
+ // Empty audit_log + tip claiming counter=999. Net: rollback.
925
+ await b.externalDb.query(
926
+ "INSERT INTO _blamejs_audit_tip (scope, atMonotonicCounter, rowHash, signedAt, fencingToken) " +
927
+ "VALUES ('audit', 999, 'rolled-hash', '0', 5)"
928
+ );
929
+ await b.externalDb.shutdown();
930
+ driver._close();
931
+
932
+ // Spawn a child that re-opens the same db file and calls
933
+ // cluster.init. The rollback check should fire and exit(1).
934
+ var spawnSync = require("child_process").spawnSync;
935
+ var indexPath = path.resolve(__dirname, "..", "index.js").replace(/\\/g, "/");
936
+ var dbPathForChild = dbPath.replace(/\\/g, "/");
937
+ var childScript =
938
+ "var b = require('" + indexPath + "');\n" +
939
+ "var sqlite = require('node:sqlite');\n" +
940
+ "var conn = new sqlite.DatabaseSync('" + dbPathForChild + "');\n" +
941
+ "var driver = {\n" +
942
+ " connect: async function () { return { id: 'c1' }; },\n" +
943
+ " query: async function (_c, sql, params) {\n" +
944
+ " var stmt = conn.prepare(sql);\n" +
945
+ " if (/^\\s*SELECT/i.test(sql) || /\\bRETURNING\\b/i.test(sql)) {\n" +
946
+ " return { rows: stmt.all.apply(stmt, params || []), rowCount: 0 };\n" +
947
+ " }\n" +
948
+ " var info = stmt.run.apply(stmt, params || []);\n" +
949
+ " return { rows: [], rowCount: info.changes };\n" +
950
+ " },\n" +
951
+ " close: async function () {},\n" +
952
+ "};\n" +
953
+ "(async function () {\n" +
954
+ " b.externalDb.init({ backends: { ops: driver } });\n" +
955
+ " await b.cluster.init({ nodeId: 'rb-child', externalDbBackend: 'ops', dialect: 'sqlite', leaseTtl: 30000, heartbeatInterval: 10000 });\n" +
956
+ " console.log('UNEXPECTED-BOOT');\n" +
957
+ "})().catch(function (e) { console.error('CHILD-ERR ' + e.message); process.exit(99); });\n";
958
+ var result = spawnSync(process.execPath, ["-e", childScript], { encoding: "utf8" });
959
+ // cluster.init throws ClusterError on rollback detection; the child
960
+ // script's catch handler exits with code 99. Pre-v0.7.0 the lib called
961
+ // process.exit(1) unilaterally; the test now asserts the controlled-throw
962
+ // path so callers can decide their own exit code.
963
+ check("rollback boot exits via the catch handler (code 99)",
964
+ result.status === 99);
965
+ check("rollback boot logs detection message",
966
+ /audit-log rollback detected/i.test(result.stderr || ""));
967
+ check("rollback boot did NOT print UNEXPECTED-BOOT (exited before continuing)",
968
+ (result.stdout || "").indexOf("UNEXPECTED-BOOT") === -1);
969
+ } finally {
970
+ fs.rmSync(tmpDir, { recursive: true, force: true });
971
+ }
972
+ }
973
+
974
+ async function testClusterAuditTipRowHashMismatch() {
975
+ // Same counter on both sides but different rowHash — row substitution
976
+ // at the chain head. Detection path: tipCounter == currentMax, but
977
+ // the row at that counter has a different hash than the tip recorded.
978
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-rb-hash-"));
979
+ var dbPath = path.join(tmpDir, "ext.db");
980
+ var driver = _makeSqliteDriver(dbPath);
981
+ try {
982
+ b.externalDb.init({
983
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
984
+ });
985
+ await b.frameworkSchema.ensureSchema({
986
+ externalDbBackend: "ops",
987
+ dialect: "sqlite",
988
+ });
989
+ await b.externalDb.query(
990
+ "INSERT INTO _blamejs_audit_log " +
991
+ "(_id, recordedAt, monotonicCounter, action, outcome, prevHash, rowHash, nonce, fencingToken) " +
992
+ "VALUES ('row-substituted', ?, 1, 'system.test.subst', 'success', '', 'WRONG-HASH', x'00000000000000000000000000000000', 1)",
993
+ [Date.now()]
994
+ );
995
+ // Tip records the OLD hash at the same counter — substitution.
996
+ await b.externalDb.query(
997
+ "INSERT INTO _blamejs_audit_tip (scope, atMonotonicCounter, rowHash, signedAt, fencingToken) " +
998
+ "VALUES ('audit', 1, 'ORIGINAL-HASH', '0', 1)"
999
+ );
1000
+ await b.externalDb.shutdown();
1001
+ driver._close();
1002
+
1003
+ var spawnSync = require("child_process").spawnSync;
1004
+ var indexPath = path.resolve(__dirname, "..", "index.js").replace(/\\/g, "/");
1005
+ var dbPathForChild = dbPath.replace(/\\/g, "/");
1006
+ var childScript =
1007
+ "var b = require('" + indexPath + "');\n" +
1008
+ "var sqlite = require('node:sqlite');\n" +
1009
+ "var conn = new sqlite.DatabaseSync('" + dbPathForChild + "');\n" +
1010
+ "var driver = {\n" +
1011
+ " connect: async function () { return { id: 'c1' }; },\n" +
1012
+ " query: async function (_c, sql, params) {\n" +
1013
+ " var stmt = conn.prepare(sql);\n" +
1014
+ " if (/^\\s*SELECT/i.test(sql) || /\\bRETURNING\\b/i.test(sql)) {\n" +
1015
+ " return { rows: stmt.all.apply(stmt, params || []), rowCount: 0 };\n" +
1016
+ " }\n" +
1017
+ " var info = stmt.run.apply(stmt, params || []);\n" +
1018
+ " return { rows: [], rowCount: info.changes };\n" +
1019
+ " },\n" +
1020
+ " close: async function () {},\n" +
1021
+ "};\n" +
1022
+ "(async function () {\n" +
1023
+ " b.externalDb.init({ backends: { ops: driver } });\n" +
1024
+ " await b.cluster.init({ nodeId: 'rb-hash-child', externalDbBackend: 'ops', dialect: 'sqlite', leaseTtl: 30000, heartbeatInterval: 10000 });\n" +
1025
+ " console.log('UNEXPECTED-BOOT');\n" +
1026
+ "})().catch(function (e) { console.error('CHILD-ERR ' + e.message); process.exit(99); });\n";
1027
+ var result = spawnSync(process.execPath, ["-e", childScript], { encoding: "utf8" });
1028
+ check("row-hash mismatch boot exits via the catch handler (code 99)",
1029
+ result.status === 99);
1030
+ check("row-hash mismatch boot logs detection message",
1031
+ /row-hash mismatch/i.test(result.stderr || ""));
1032
+ } finally {
1033
+ fs.rmSync(tmpDir, { recursive: true, force: true });
1034
+ }
1035
+ }
1036
+
1037
+ async function testClusterAuditFlushNoRecursionHang() {
1038
+ // Regression test for :
1039
+ // Before the fix, audit.flush() in cluster mode hung forever because
1040
+ // each drained event wrote through external-db, externalDb.query
1041
+ // emitted a system.externaldb.query audit event back into the same
1042
+ // handler buffer, and handlers.drain's while-loop processed those new
1043
+ // items in the same call — so the buffer refilled as fast as it
1044
+ // emptied. The fix bounds drain to a snapshot of the buffer at start
1045
+ // (matching the documented recursion-safety contract). This test
1046
+ // proves flush() returns within a tight wall-clock budget in cluster
1047
+ // mode under exactly the producer/consumer cycle that triggered the
1048
+ // hang.
1049
+ b.cluster._resetForTest();
1050
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-flush-rec-"));
1051
+ var dbPath = path.join(tmpDir, "ext.db");
1052
+ var driver = _makeSqliteDriver(dbPath);
1053
+ try {
1054
+ await setupTestDb(tmpDir);
1055
+ await b.audit.flush(); // drain any boot-time emits in single-node
1056
+ b.externalDb.init({
1057
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
1058
+ });
1059
+ await b.frameworkSchema.ensureSchema({
1060
+ externalDbBackend: "ops",
1061
+ dialect: "sqlite",
1062
+ });
1063
+ await b.cluster.init({
1064
+ nodeId: "flush-rec-1",
1065
+ externalDbBackend: "ops",
1066
+ dialect: "sqlite",
1067
+ leaseTtl: b.constants.TIME.seconds(30),
1068
+ heartbeatInterval: b.constants.TIME.seconds(10),
1069
+ });
1070
+
1071
+ // record() bypasses the buffer, but the underlying externalDb.query
1072
+ // emits a system.externaldb.query event INTO the buffer. Subsequent
1073
+ // flush() drains that — and each drained event itself writes through
1074
+ // external-db, emitting more events. Pre-fix: hang. Post-fix: drain
1075
+ // is bounded; lingering events stay for the next call.
1076
+ await b.audit.record({
1077
+ action: "system.test.flush_recursion",
1078
+ outcome: "success",
1079
+ actor: { userId: "rec-test" },
1080
+ });
1081
+
1082
+ // The Promise.race against a 5s timeout is the no-hang regression
1083
+ // guard — if flush() truly hangs it never resolves, raced lands as
1084
+ // "TIMEOUT". Don't add a separate elapsed-< 5000 check: it's
1085
+ // tautologically true when raced === "done" (the timeout would have
1086
+ // fired first otherwise) and produces a Windows boundary flake when
1087
+ // event-loop drift puts the post-await Date.now() at 5001ms.
1088
+ var raced = await Promise.race([
1089
+ b.audit.flush().then(function () { return "done"; }),
1090
+ new Promise(function (r) { setTimeout(function () { r("TIMEOUT"); }, 5000); }),
1091
+ ]);
1092
+ check("audit.flush returns (no recursion hang)", raced === "done");
1093
+ } finally {
1094
+ try { await b.cluster.shutdown(); } catch (_e) {}
1095
+ try { await b.externalDb.shutdown(); } catch (_e) {}
1096
+ driver._close();
1097
+ await teardownTestDb(tmpDir);
1098
+ }
1099
+ }
1100
+
1101
+ async function testClusterAuditTipFencedOutErrorSurface() {
1102
+ // Verify that audit.js's _upsertAuditTip surfaces
1103
+ // ClusterError(code=FENCED_OUT, permanent=true) when the fence rejects
1104
+ // the write. This catches a regression where the original
1105
+ // UPDATE-then-INSERT-if-missing path swallowed silently — operators
1106
+ // MUST see fence rejection.
1107
+ //
1108
+ // We bypass audit.record/flush (which crosses the single-node →
1109
+ // cluster-mode boundary mid-buffer, an unrelated complication) and
1110
+ // exercise audit.checkpoint() directly: insert one audit_log row by
1111
+ // hand into external-db, pre-seed the audit-tip with a higher token
1112
+ // than the local lease has, and assert the checkpoint surfaces the
1113
+ // FENCED_OUT class+code.
1114
+ b.cluster._resetForTest();
1115
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-fence-err-"));
1116
+ var dbPath = path.join(tmpDir, "ext.db");
1117
+ var driver = _makeSqliteDriver(dbPath);
1118
+ try {
1119
+ // Full framework boot needed because checkpoint() invokes audit-sign
1120
+ // (signature over the chain head) which requires the signing key
1121
+ // initialized via db.init.
1122
+ await setupTestDb(tmpDir);
1123
+ b.externalDb.init({
1124
+ backends: { "ops": { connect: driver.connect, query: driver.query, close: driver.close } },
1125
+ });
1126
+ await b.frameworkSchema.ensureSchema({
1127
+ externalDbBackend: "ops",
1128
+ dialect: "sqlite",
1129
+ });
1130
+
1131
+ await b.cluster.init({
1132
+ nodeId: "fence-err-test-1",
1133
+ externalDbBackend: "ops",
1134
+ dialect: "sqlite",
1135
+ leaseTtl: b.constants.TIME.seconds(30),
1136
+ heartbeatInterval: b.constants.TIME.seconds(10),
1137
+ });
1138
+
1139
+ // Insert one audit_log row directly so checkpoint has a tip to
1140
+ // anchor. clusterStorage rewrites `audit_log` → `_blamejs_audit_log`
1141
+ // in cluster mode, and we use `?` placeholders so the dispatcher's
1142
+ // dialect translation handles the parameterization.
1143
+ await b.clusterStorage.execute(
1144
+ "INSERT INTO audit_log " +
1145
+ " (_id, recordedAt, monotonicCounter, action, outcome, " +
1146
+ " prevHash, rowHash, nonce, fencingToken) " +
1147
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
1148
+ ["fence-row", Date.now(), 1, "system.test.fence", "success",
1149
+ "", "fence-hash-1", Buffer.alloc(16), 1]
1150
+ );
1151
+
1152
+ // Pre-seed _blamejs_audit_tip with a token (99) higher than this
1153
+ // node's lease (=1 right after acquire). The checkpoint's
1154
+ // _upsertAuditTip will write fencingToken=1, which is below the
1155
+ // stored 99 — the WHERE-clause guard rejects it.
1156
+ await b.clusterStorage.execute(
1157
+ "INSERT INTO _blamejs_audit_tip " +
1158
+ " (scope, atMonotonicCounter, rowHash, signedAt, fencingToken) " +
1159
+ "VALUES ('audit', ?, ?, ?, ?) " +
1160
+ "ON CONFLICT (scope) DO UPDATE SET " +
1161
+ " fencingToken = EXCLUDED.fencingToken",
1162
+ [0, "preseed", "0", 99]
1163
+ );
1164
+
1165
+ var threw = null;
1166
+ try { await b.audit.checkpoint(); }
1167
+ catch (e) { threw = e; }
1168
+
1169
+ check("checkpoint: fenced-out throws", threw !== null);
1170
+ check("checkpoint: error is ClusterError",
1171
+ threw && threw.isClusterError === true);
1172
+ check("checkpoint: error code is FENCED_OUT",
1173
+ threw && threw.code === "FENCED_OUT");
1174
+ check("checkpoint: error is permanent",
1175
+ threw && threw.permanent === true);
1176
+ } finally {
1177
+ try { await b.cluster.shutdown(); } catch (_e) {}
1178
+ try { await b.externalDb.shutdown(); } catch (_e) {}
1179
+ driver._close();
1180
+ await teardownTestDb(tmpDir);
1181
+ }
1182
+ }
1183
+
1184
+ async function testAuditChain() {
1185
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-audit-"));
1186
+ try {
1187
+ await setupTestDb(tmpDir);
1188
+
1189
+ // Unregistered namespace rejected
1190
+ var nsRejected = false;
1191
+ try { await b.audit.record({ action: "orders.created", outcome: "success" }); }
1192
+ catch (_) { nsRejected = true; }
1193
+ check("unregistered namespace rejected", nsRejected);
1194
+
1195
+ // Register + record
1196
+ b.audit.registerNamespace("orders");
1197
+ var ev1 = await b.audit.record({
1198
+ actor: { userId: "user-1", ip: "1.2.3.4" },
1199
+ action: "orders.created",
1200
+ resource: { kind: "order", id: "ord-1" },
1201
+ outcome: "success",
1202
+ metadata: { total: 99.95 },
1203
+ });
1204
+ check("audit.record returns row with rowHash", typeof ev1.rowHash === "string" && ev1.rowHash.length === 128);
1205
+ check("first row's prevHash is ZERO_HASH", ev1.prevHash === b.auditChain.ZERO_HASH);
1206
+
1207
+ var ev2 = await b.audit.record({
1208
+ actor: { userId: "user-1", ip: "1.2.3.4" },
1209
+ action: "auth.login.success",
1210
+ resource: { kind: "user", id: "user-1" },
1211
+ outcome: "success",
1212
+ });
1213
+ check("second row's prevHash = first row's rowHash", ev2.prevHash === ev1.rowHash);
1214
+ check("monotonicCounter increments", ev2.monotonicCounter === ev1.monotonicCounter + 1);
1215
+
1216
+ // Invalid action format
1217
+ var actionRejected = false;
1218
+ try { await b.audit.record({ action: "no-dot", outcome: "success" }); }
1219
+ catch (_) { actionRejected = true; }
1220
+ check("malformed action rejected", actionRejected);
1221
+
1222
+ // Invalid outcome
1223
+ var outcomeRejected = false;
1224
+ try { await b.audit.record({ action: "auth.login.success", outcome: "ok" }); }
1225
+ catch (_) { outcomeRejected = true; }
1226
+ check("invalid outcome rejected", outcomeRejected);
1227
+
1228
+ // safeEmit: fire-and-forget shape with default-fill + try/catch.
1229
+ // Surface contract: never throws on malformed input; valid events
1230
+ // get queued via the handler (full end-to-end landing depends on
1231
+ // cluster init, covered by integration tests elsewhere).
1232
+ check("audit.safeEmit is exposed", typeof b.audit.safeEmit === "function");
1233
+ var threwOnMalformed = null;
1234
+ try {
1235
+ b.audit.safeEmit();
1236
+ b.audit.safeEmit(null);
1237
+ b.audit.safeEmit({}); // missing action
1238
+ b.audit.safeEmit({ outcome: "success" }); // missing action
1239
+ b.audit.safeEmit("not-an-object");
1240
+ } catch (e) { threwOnMalformed = e; }
1241
+ check("safeEmit: malformed inputs silently dropped", threwOnMalformed === null);
1242
+ var threwOnValid = null;
1243
+ try { b.audit.safeEmit({ action: "orders.shipped" }); }
1244
+ catch (e) { threwOnValid = e; }
1245
+ check("safeEmit: valid event accepted without throw", threwOnValid === null);
1246
+
1247
+ // Verify chain is intact
1248
+ var v1 = await b.audit.verify();
1249
+ check("audit.verify() ok after valid records", v1.ok === true && v1.rowsVerified === 2);
1250
+
1251
+ // Query by various criteria
1252
+ var byUser = await b.audit.query({ actorUserId: "user-1" });
1253
+ check("query by sealed actorUserId returns rows", byUser.length === 2);
1254
+ check("query result rows are unsealed", byUser[0].actorUserId === "user-1");
1255
+ var byAction = await b.audit.query({ action: "auth.login.success" });
1256
+ check("query by action returns matching", byAction.length === 1);
1257
+ var byKind = await b.audit.query({ resourceKind: "order" });
1258
+ check("query by resourceKind returns matching", byKind.length === 1);
1259
+ } finally {
1260
+ await teardownTestDb(tmpDir);
1261
+ }
1262
+ }
1263
+
1264
+ async function testAuditChainBreak() {
1265
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-broken-"));
1266
+ try {
1267
+ await setupTestDb(tmpDir);
1268
+ b.audit.registerNamespace("test");
1269
+ await b.audit.record({ action: "test.event", outcome: "success" });
1270
+ await b.audit.record({ action: "test.event", outcome: "success" });
1271
+ var v1 = await b.audit.verify();
1272
+ check("chain ok before tampering", v1.ok === true);
1273
+
1274
+ // Manually corrupt a row's reason field. Currently the audit_log
1275
+ // table has BEFORE-UPDATE/DELETE triggers blocking direct mutation —
1276
+ // simulating a raw-DB-file tamper that bypassed those guards by
1277
+ // dropping the triggers around the corruption.
1278
+ b.db.runSql("DROP TRIGGER IF EXISTS no_update_audit_log");
1279
+ b.db.prepare('UPDATE audit_log SET reason = ? WHERE monotonicCounter = 1').run("vault:tampered-but-not-actually-sealed");
1280
+ b.db.runSql("CREATE TRIGGER IF NOT EXISTS no_update_audit_log BEFORE UPDATE ON audit_log BEGIN SELECT RAISE(ABORT, 'audit_log is append-only — UPDATE prohibited'); END");
1281
+ var v2 = await b.audit.verify();
1282
+ check("chain detected after row tampering", v2.ok === false);
1283
+ check("chain break reports breakAt index", v2.breakAt === 0 || v2.breakAt === 1);
1284
+ check("chain break reports rowHash mismatch reason",
1285
+ v2.reason === "rowHash mismatch" || v2.reason === "prevHash mismatch");
1286
+ } finally {
1287
+ await teardownTestDb(tmpDir);
1288
+ }
1289
+ }
1290
+
1291
+ async function testAuditSelfLogging() {
1292
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-selflog-"));
1293
+ try {
1294
+ await setupTestDb(tmpDir);
1295
+ b.audit.registerNamespace("test");
1296
+ await b.audit.record({ action: "test.event", outcome: "success" });
1297
+ await b.audit.record({ action: "test.event", outcome: "success" });
1298
+
1299
+ // A query auto-records an audit.read event before returning rows
1300
+ var beforeCount = b.db.from("audit_log").count();
1301
+ var rows = await b.audit.query({ action: "test.event" });
1302
+ var afterCount = b.db.from("audit_log").count();
1303
+ check("query returned both test.event rows", rows.length === 2);
1304
+ check("query auto-recorded an audit.read event", afterCount === beforeCount + 1);
1305
+
1306
+ // The audit.read row exists
1307
+ var readRows = await b.audit.query({ action: "audit.read" });
1308
+ check("audit.read events queryable directly", readRows.length >= 1);
1309
+ check("audit.read row has criteria metadata",
1310
+ readRows[0].metadata && /criteria/.test(readRows[0].metadata));
1311
+
1312
+ // Querying for audit.read does NOT recursively self-log (else infinite chain)
1313
+ var beforeRecursionCheck = b.db.from("audit_log").count();
1314
+ await b.audit.query({ action: "audit.read" });
1315
+ var afterRecursionCheck = b.db.from("audit_log").count();
1316
+ check("query for audit.read does NOT auto-self-log", afterRecursionCheck === beforeRecursionCheck);
1317
+
1318
+ // Audit chain still verifies through all the self-logging
1319
+ var v = await b.audit.verify();
1320
+ check("audit chain ok after self-log activity", v.ok === true);
1321
+ } finally {
1322
+ await teardownTestDb(tmpDir);
1323
+ }
1324
+ }
1325
+
1326
+ async function testBeginTrace() {
1327
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-trace-"));
1328
+ try {
1329
+ await setupTestDb(tmpDir);
1330
+ b.audit.registerNamespace("test");
1331
+
1332
+ var t1 = b.audit.beginTrace();
1333
+ var t2 = b.audit.beginTrace();
1334
+ check("beginTrace returns 32-hex string", typeof t1 === "string" && t1.length === 32 && /^[0-9a-f]+$/.test(t1));
1335
+ check("beginTrace returns unique values", t1 !== t2);
1336
+
1337
+ // Apps thread the traceId through linked events
1338
+ var ev1 = await b.audit.record({
1339
+ action: "test.start",
1340
+ outcome: "success",
1341
+ metadata: { traceId: t1 },
1342
+ });
1343
+ var ev2 = await b.audit.record({
1344
+ action: "test.continue",
1345
+ outcome: "success",
1346
+ metadata: { traceId: t1, parentEventId: ev1._id },
1347
+ });
1348
+
1349
+ // Query and verify trace correlation is queryable from metadata
1350
+ var rows = await b.audit.query({ action: "test.start" });
1351
+ var meta = JSON.parse(rows[0].metadata);
1352
+ check("traceId persists into audit row metadata", meta.traceId === t1);
1353
+
1354
+ var rows2 = await b.audit.query({ action: "test.continue" });
1355
+ var meta2 = JSON.parse(rows2[0].metadata);
1356
+ check("parentEventId persists into audit row", meta2.parentEventId === ev1._id);
1357
+ check("traceId is shared across linked events", meta2.traceId === t1);
1358
+
1359
+ void ev2;
1360
+ } finally {
1361
+ await teardownTestDb(tmpDir);
1362
+ }
1363
+ }
1364
+
1365
+ async function testConsent() {
1366
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-consent-"));
1367
+ try {
1368
+ await setupTestDb(tmpDir);
1369
+
1370
+ var subjectId = "user-7";
1371
+ check("isGranted is false before grant", b.consent.isGranted({ subjectId, purpose: "marketing.email" }) === false);
1372
+
1373
+ await b.consent.grant({
1374
+ subjectId: subjectId,
1375
+ purpose: "marketing.email",
1376
+ lawfulBasis: "consent",
1377
+ scope: { channels: ["email"], topics: ["product-updates"] },
1378
+ channel: "web_form_v2",
1379
+ evidenceRef: "/evidence/forms/2026-04-25T...",
1380
+ });
1381
+ check("isGranted true after grant", b.consent.isGranted({ subjectId, purpose: "marketing.email" }) === true);
1382
+
1383
+ await b.consent.withdraw({ subjectId, purpose: "marketing.email" });
1384
+ check("isGranted false after withdraw", b.consent.isGranted({ subjectId, purpose: "marketing.email" }) === false);
1385
+
1386
+ var hist = b.consent.history(subjectId);
1387
+ check("history returns 2 events", hist.length === 2);
1388
+ check("history first event is grant", hist[0].action === "granted");
1389
+ check("history second event is withdraw", hist[1].action === "withdrawn");
1390
+ check("history unsealed subjectId", hist[0].subjectId === subjectId);
1391
+
1392
+ var cv = await b.consent.verify();
1393
+ check("consent.verify() ok", cv.ok === true && cv.rowsVerified === 2);
1394
+
1395
+ // Invalid lawful basis
1396
+ var basisRejected = false;
1397
+ try { await b.consent.grant({ subjectId, purpose: "x", lawfulBasis: "bogus", channel: "x" }); }
1398
+ catch (_) { basisRejected = true; }
1399
+ check("invalid lawfulBasis rejected", basisRejected);
1400
+ } finally {
1401
+ await teardownTestDb(tmpDir);
1402
+ }
1403
+ }
1404
+
1405
+ async function testSubjectRights() {
1406
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-subject-"));
1407
+ try {
1408
+ b.vault._resetForTest();
1409
+ b.db._resetForTest();
1410
+ await b.vault.init({ dataDir: tmpDir, mode: "plaintext" });
1411
+ await b.db.init({
1412
+ dataDir: tmpDir,
1413
+ atRest: "plain",
1414
+ auditSigning: { mode: "plaintext" },
1415
+ schema: [
1416
+ {
1417
+ name: "users",
1418
+ columns: {
1419
+ _id: "TEXT PRIMARY KEY",
1420
+ email: "TEXT",
1421
+ emailHash: "TEXT",
1422
+ name: "TEXT",
1423
+ },
1424
+ indexes: ["emailHash"],
1425
+ sealedFields: ["email", "name"],
1426
+ derivedHashes: { emailHash: { from: "email", normalize: function (v) { return String(v).toLowerCase(); } } },
1427
+ subjectField: "_id",
1428
+ personalDataCategories: { email: "email", name: "name" },
1429
+ },
1430
+ {
1431
+ name: "orders",
1432
+ columns: {
1433
+ _id: "TEXT PRIMARY KEY",
1434
+ userId: "TEXT",
1435
+ userIdHash: "TEXT",
1436
+ amount: "REAL",
1437
+ },
1438
+ indexes: ["userIdHash"],
1439
+ sealedFields: [],
1440
+ derivedHashes: { userIdHash: { from: "userId" } },
1441
+ subjectField: "userId",
1442
+ personalDataCategories: {},
1443
+ },
1444
+ ],
1445
+ });
1446
+
1447
+ b.db.from("users").insertOne({ _id: "u-alice", email: "alice@x.com", name: "Alice" });
1448
+ b.db.from("users").insertOne({ _id: "u-bob", email: "bob@x.com", name: "Bob" });
1449
+ b.db.from("orders").insertOne({ _id: "o-1", userId: "u-alice", amount: 99.95 });
1450
+ b.db.from("orders").insertOne({ _id: "o-2", userId: "u-alice", amount: 12.50 });
1451
+ b.db.from("orders").insertOne({ _id: "o-3", userId: "u-bob", amount: 7.00 });
1452
+
1453
+ // Export
1454
+ var dump = b.subject.export("u-alice", { reason: "Art. 15 access request 2026-04-25" });
1455
+ check("subject.export returns dump for alice", dump.users && dump.users.length === 1);
1456
+ check("subject.export decrypts sealed fields", dump.users[0].email === "alice@x.com");
1457
+ check("subject.export walks orders too", dump.orders && dump.orders.length === 2);
1458
+
1459
+ // Rectify
1460
+ var ok = b.subject.rectify("u-alice", {
1461
+ table: "users",
1462
+ id: "u-alice",
1463
+ changes: { name: "Alice Updated" },
1464
+ reason: "Art. 16 rectification 2026-04-25",
1465
+ });
1466
+ check("rectify returns true", ok === true);
1467
+ var aliceAfter = b.db.from("users").where({ _id: "u-alice" }).first();
1468
+ check("rectify wrote new value", aliceAfter.name === "Alice Updated");
1469
+
1470
+ // Erase requires both acknowledgements
1471
+ var noAckRejected = false;
1472
+ try { b.subject.erase("u-alice", { reason: "Art. 17", acknowledgements: ["no-litigation-hold"] }); }
1473
+ catch (_) { noAckRejected = true; }
1474
+ check("erase without all acknowledgements rejected", noAckRejected);
1475
+
1476
+ // Erase with all acks
1477
+ var result = b.subject.erase("u-alice", {
1478
+ reason: "Art. 17 erasure request 2026-04-25 ticket #4471",
1479
+ acknowledgements: ["no-litigation-hold", "no-statutory-retention-required"],
1480
+ });
1481
+ check("erase returns rowsDeleted", result.rowsDeleted >= 3);
1482
+ check("alice gone from users", b.db.from("users").where({ _id: "u-alice" }).first() === null);
1483
+ check("alice's orders gone", b.db.from("orders").where({ userIdHash: b.db.hashFor("orders", "userId", "u-alice") }).all().length === 0);
1484
+ check("bob still present", b.db.from("users").where({ _id: "u-bob" }).first() !== null);
1485
+
1486
+ // Erasure marker recorded
1487
+ var erasureRow = b.db.prepare("SELECT subjectIdHash FROM _blamejs_subject_erasures").all();
1488
+ check("subject erasure marker recorded", erasureRow.length === 1);
1489
+
1490
+ // Restrict / isRestricted
1491
+ check("isRestricted false initially", b.subject.isRestricted("u-bob") === false);
1492
+ b.subject.restrict("u-bob", { on: true, reason: "Art. 18 contested accuracy" });
1493
+ check("isRestricted true after restrict", b.subject.isRestricted("u-bob") === true);
1494
+ b.subject.restrict("u-bob", { on: false });
1495
+ check("isRestricted false after lift", b.subject.isRestricted("u-bob") === false);
1496
+
1497
+ // Audit chain still intact after all this activity
1498
+ var av = await b.audit.verify();
1499
+ check("audit chain intact through subject ops", av.ok === true);
1500
+ } finally {
1501
+ await teardownTestDb(tmpDir);
1502
+ }
1503
+ }
1504
+
1505
+ async function testAppendOnlyTriggers() {
1506
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-trig-"));
1507
+ try {
1508
+ await setupTestDb(tmpDir);
1509
+ b.audit.registerNamespace("test");
1510
+ await b.audit.record({ action: "test.event", outcome: "success" });
1511
+
1512
+ var deleteRejected = false;
1513
+ try { b.db.runSql("DELETE FROM audit_log"); }
1514
+ catch (e) { deleteRejected = /append-only|prohibited/i.test(e.message); }
1515
+ check("DELETE on audit_log raises ABORT", deleteRejected);
1516
+
1517
+ var updateRejected = false;
1518
+ try { b.db.runSql("UPDATE audit_log SET outcome = 'denied' WHERE 1=1"); }
1519
+ catch (e) { updateRejected = /append-only|prohibited/i.test(e.message); }
1520
+ check("UPDATE on audit_log raises ABORT", updateRejected);
1521
+
1522
+ // consent_log
1523
+ await b.consent.grant({ subjectId: "u-1", purpose: "x", lawfulBasis: "consent", channel: "api" });
1524
+ var conDelRejected = false;
1525
+ try { b.db.runSql("DELETE FROM consent_log"); }
1526
+ catch (e) { conDelRejected = /append-only|prohibited/i.test(e.message); }
1527
+ check("DELETE on consent_log raises ABORT", conDelRejected);
1528
+
1529
+ // INSERT still works (the framework's API uses it constantly above)
1530
+ var counts = b.db.prepare("SELECT (SELECT COUNT(*) FROM audit_log) AS a, (SELECT COUNT(*) FROM consent_log) AS c").get();
1531
+ check("INSERT on audit_log still works", counts.a >= 1);
1532
+ check("INSERT on consent_log still works", counts.c >= 1);
1533
+ } finally {
1534
+ await teardownTestDb(tmpDir);
1535
+ }
1536
+ }
1537
+
1538
+ async function testForeignKeys() {
1539
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-fk-"));
1540
+ try {
1541
+ process.env.BLAMEJS_SKIP_NTP_CHECK = "1";
1542
+ b.vault._resetForTest();
1543
+ b.db._resetForTest();
1544
+ await b.vault.init({ dataDir: tmpDir, mode: "plaintext" });
1545
+ await b.db.init({
1546
+ dataDir: tmpDir,
1547
+ atRest: "plain",
1548
+ auditSigning: { mode: "plaintext" },
1549
+ schema: [
1550
+ {
1551
+ name: "users",
1552
+ columns: { _id: "TEXT", email: "TEXT", emailHash: "TEXT" },
1553
+ primaryKey: "_id",
1554
+ indexes: ["emailHash"],
1555
+ sealedFields: ["email"],
1556
+ derivedHashes: { emailHash: { from: "email", normalize: function (v) { return String(v).toLowerCase(); } } },
1557
+ },
1558
+ {
1559
+ name: "orders",
1560
+ columns: { _id: "TEXT", userId: "TEXT NOT NULL", amount: "REAL" },
1561
+ primaryKey: "_id",
1562
+ foreignKeys: [{ column: "userId", references: "users._id", onDelete: "CASCADE" }],
1563
+ },
1564
+ ],
1565
+ });
1566
+
1567
+ // Verify foreign_keys pragma is ON
1568
+ var fkPragma = b.db.prepare("PRAGMA foreign_keys").get();
1569
+ check("foreign_keys pragma is enabled", fkPragma.foreign_keys === 1);
1570
+
1571
+ // Verify FK declared in DDL
1572
+ var fkInfo = b.db.prepare("PRAGMA foreign_key_list(orders)").all();
1573
+ check("orders has 1 FK declared", fkInfo.length === 1);
1574
+ check("FK references users(_id)", fkInfo[0].table === "users" && fkInfo[0].from === "userId" && fkInfo[0].to === "_id");
1575
+ check("FK on_delete is CASCADE", fkInfo[0].on_delete === "CASCADE");
1576
+
1577
+ // Insert valid user + order
1578
+ b.db.from("users").insertOne({ _id: "u-1", email: "a@b.com" });
1579
+ b.db.from("orders").insertOne({ _id: "o-1", userId: "u-1", amount: 100 });
1580
+ check("valid order insert succeeds", b.db.from("orders").where({ _id: "o-1" }).first() !== null);
1581
+
1582
+ // FK violation: order with non-existent userId
1583
+ var fkViolated = false;
1584
+ try { b.db.from("orders").insertOne({ _id: "o-2", userId: "u-nonexistent", amount: 50 }); }
1585
+ catch (e) { fkViolated = /FOREIGN KEY|constraint/i.test(e.message); }
1586
+ check("FK violation rejects insert", fkViolated);
1587
+
1588
+ // Cascade delete: deleting user removes their orders
1589
+ b.db.from("users").where({ _id: "u-1" }).deleteOne();
1590
+ check("ON DELETE CASCADE removes child rows", b.db.from("orders").where({ _id: "o-1" }).first() === null);
1591
+ } finally {
1592
+ await teardownTestDb(tmpDir);
1593
+ }
1594
+ }
1595
+
1596
+ async function testTableMetadata() {
1597
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-meta-"));
1598
+ try {
1599
+ process.env.BLAMEJS_SKIP_NTP_CHECK = "1";
1600
+ b.vault._resetForTest();
1601
+ b.db._resetForTest();
1602
+ await b.vault.init({ dataDir: tmpDir, mode: "plaintext" });
1603
+ await b.db.init({
1604
+ dataDir: tmpDir,
1605
+ atRest: "plain",
1606
+ auditSigning: { mode: "plaintext" },
1607
+ schema: [
1608
+ {
1609
+ name: "items",
1610
+ columns: { _id: "TEXT", ownerId: "TEXT", name: "TEXT", nameHash: "TEXT" },
1611
+ primaryKey: "_id",
1612
+ foreignKeys: [{ column: "ownerId", references: "users._id", onDelete: "SET NULL" }],
1613
+ indexes: ["nameHash"],
1614
+ sealedFields: ["name"],
1615
+ derivedHashes: { nameHash: { from: "name" } },
1616
+ subjectField: "ownerId",
1617
+ personalDataCategories: { name: "label" },
1618
+ },
1619
+ // users table with no FKs
1620
+ { name: "users", columns: { _id: "TEXT" }, primaryKey: "_id" },
1621
+ ],
1622
+ });
1623
+
1624
+ var meta = b.db.getTableMetadata("items");
1625
+ check("metadata returns object", typeof meta === "object" && meta !== null);
1626
+ check("metadata.primaryKey is array", Array.isArray(meta.primaryKey) && meta.primaryKey[0] === "_id");
1627
+ check("metadata.foreignKeys captured", meta.foreignKeys.length === 1 && meta.foreignKeys[0].references === "users._id");
1628
+ check("metadata.sealedFields captured", meta.sealedFields[0] === "name");
1629
+ check("metadata.subjectField captured", meta.subjectField === "ownerId");
1630
+ check("metadata.personalDataCategories captured", meta.personalDataCategories.name === "label");
1631
+
1632
+ // Framework tables also show up in metadata
1633
+ var auditMeta = b.db.getTableMetadata("audit_log");
1634
+ check("audit_log metadata available", auditMeta !== null);
1635
+ check("audit_log primaryKey is _id", auditMeta.primaryKey[0] === "_id");
1636
+
1637
+ // Mutating the snapshot doesn't affect framework state
1638
+ meta.foreignKeys.push({ column: "fake" });
1639
+ var freshMeta = b.db.getTableMetadata("items");
1640
+ check("metadata snapshot is deep-copied", freshMeta.foreignKeys.length === 1);
1641
+ } finally {
1642
+ await teardownTestDb(tmpDir);
1643
+ }
1644
+ }
1645
+
1646
+ async function testAuditSignDefaultsToSlhDsa() {
1647
+ // First-run plaintext init in a fresh data directory should generate
1648
+ // an SLH-DSA-SHAKE-256f keypair (the current default), and the
1649
+ // on-disk file should record `algorithm: "slh-dsa-shake-256f"` so
1650
+ // future loads dispatch correctly without re-detection.
1651
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-asd-"));
1652
+ try {
1653
+ // This test inspects the on-disk JSON content of audit-sign.key,
1654
+ // which only exists in plaintext audit-signing mode. Override
1655
+ // setupTestDb's secure-mode default explicitly.
1656
+ process.env.BLAMEJS_SKIP_NTP_CHECK = "1";
1657
+ b.cluster._resetForTest();
1658
+ b.audit._resetForTest();
1659
+ b.vault._resetForTest();
1660
+ b.db._resetForTest();
1661
+ await b.vault.init({ dataDir: tmpDir, mode: "plaintext" });
1662
+ await b.db.init({
1663
+ dataDir: tmpDir,
1664
+ atRest: "plain",
1665
+ auditSigning: { mode: "plaintext" },
1666
+ schema: [],
1667
+ });
1668
+ check("auditSign.getAlgorithm is exposed",
1669
+ typeof b.auditSign.getAlgorithm === "function");
1670
+ check("auditSign default alg is SLH-DSA-SHAKE-256f",
1671
+ b.auditSign.getAlgorithm() === "slh-dsa-shake-256f");
1672
+ check("auditSign exposes DEFAULT_SIGNING_ALG constant",
1673
+ b.auditSign.DEFAULT_SIGNING_ALG === "slh-dsa-shake-256f");
1674
+ check("auditSign exposes SUPPORTED_SIGNING_ALGS",
1675
+ Array.isArray(b.auditSign.SUPPORTED_SIGNING_ALGS) &&
1676
+ b.auditSign.SUPPORTED_SIGNING_ALGS.indexOf("slh-dsa-shake-256f") !== -1 &&
1677
+ b.auditSign.SUPPORTED_SIGNING_ALGS.indexOf("ml-dsa-87") !== -1);
1678
+
1679
+ // On-disk file records the algorithm
1680
+ var keyJson = JSON.parse(fs.readFileSync(path.join(tmpDir, "audit-sign.key"), "utf8"));
1681
+ check("on-disk key file records algorithm field",
1682
+ keyJson.algorithm === "slh-dsa-shake-256f");
1683
+ check("on-disk public key is SLH-DSA SPKI PEM",
1684
+ /BEGIN PUBLIC KEY/.test(keyJson.publicKey));
1685
+
1686
+ // Sign + verify round-trip works with the SLH-DSA-SHAKE-256f key
1687
+ var sig = b.auditSign.sign("hello from slh-dsa");
1688
+ check("SLH-DSA sign returns a Buffer", Buffer.isBuffer(sig));
1689
+ // SLH-DSA-SHAKE-256f signatures are ~50 KB
1690
+ check("SLH-DSA-SHAKE-256f signature size matches FIPS 205 (~50 KB)",
1691
+ sig.length > 49000 && sig.length < 51000);
1692
+ check("SLH-DSA verify accepts the signature",
1693
+ b.auditSign.verify("hello from slh-dsa", sig) === true);
1694
+ check("SLH-DSA verify rejects altered payload",
1695
+ b.auditSign.verify("hello from slh-dsa!", sig) === false);
1696
+ } finally {
1697
+ await teardownTestDb(tmpDir);
1698
+ }
1699
+ }
1700
+
1701
+ async function testAuditSignMlDsaOptIn() {
1702
+ // Operators with throughput-sensitive deployments can opt into
1703
+ // ml-dsa-87 at db.init via auditSigning: { algorithm: "ml-dsa-87" }.
1704
+ // Verify the option propagates and produces a working ML-DSA-87 key.
1705
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-asm-"));
1706
+ try {
1707
+ process.env.BLAMEJS_SKIP_NTP_CHECK = "1";
1708
+ process.env.BLAMEJS_AUDIT_SIGNING_MODE = "plaintext";
1709
+ b.cluster._resetForTest();
1710
+ b.audit._resetForTest();
1711
+ b.vault._resetForTest();
1712
+ b.db._resetForTest();
1713
+ await b.vault.init({ dataDir: tmpDir, mode: "plaintext" });
1714
+ await b.db.init({
1715
+ dataDir: tmpDir,
1716
+ atRest: "plain",
1717
+ auditSigning: { mode: "plaintext", algorithm: "ml-dsa-87" },
1718
+ schema: [],
1719
+ });
1720
+
1721
+ check("opt-in alg honored in keys.algorithm",
1722
+ b.auditSign.getAlgorithm() === "ml-dsa-87");
1723
+ var keyJson = JSON.parse(fs.readFileSync(path.join(tmpDir, "audit-sign.key"), "utf8"));
1724
+ check("on-disk key file records ml-dsa-87",
1725
+ keyJson.algorithm === "ml-dsa-87");
1726
+
1727
+ var sig = b.auditSign.sign("hello from ml-dsa-87");
1728
+ // ML-DSA-87 signatures are ~5 KB — order-of-magnitude smaller than SLH-DSA
1729
+ check("ML-DSA-87 signature size matches FIPS 204 (~5 KB)",
1730
+ sig.length > 4000 && sig.length < 6000);
1731
+ check("ML-DSA-87 verify round-trip",
1732
+ b.auditSign.verify("hello from ml-dsa-87", sig) === true);
1733
+ } finally {
1734
+ await teardownTestDb(tmpDir);
1735
+ }
1736
+ }
1737
+
1738
+ async function testAuditSignLegacyFileBackcompat() {
1739
+ // Pre-v1 compat-shim sweep removed the implicit ml-dsa-87 fallback
1740
+ // for key files missing the `algorithm` field. Such files now throw
1741
+ // KEY_FILE_MISSING_ALG at boot — operators rotate the key (deletes
1742
+ // the file and boots fresh) or hand-edit to add the field.
1743
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-asl-"));
1744
+ try {
1745
+ process.env.BLAMEJS_SKIP_NTP_CHECK = "1";
1746
+
1747
+ var nodeCrypto = require("crypto");
1748
+ var pair = nodeCrypto.generateKeyPairSync("ml-dsa-87", {
1749
+ publicKeyEncoding: { type: "spki", format: "pem" },
1750
+ privateKeyEncoding: { type: "pkcs8", format: "pem" },
1751
+ });
1752
+ fs.writeFileSync(
1753
+ path.join(tmpDir, "audit-sign.key"),
1754
+ JSON.stringify({ publicKey: pair.publicKey, privateKey: pair.privateKey }, null, 2),
1755
+ { mode: 0o600 }
1756
+ );
1757
+
1758
+ process.env.BLAMEJS_AUDIT_SIGNING_MODE = "plaintext";
1759
+ b.cluster._resetForTest();
1760
+ b.audit._resetForTest();
1761
+ b.vault._resetForTest();
1762
+ b.db._resetForTest();
1763
+ await b.vault.init({ dataDir: tmpDir, mode: "plaintext" });
1764
+
1765
+ var threw = null;
1766
+ try {
1767
+ await b.db.init({
1768
+ dataDir: tmpDir,
1769
+ atRest: "plain",
1770
+ auditSigning: { mode: "plaintext" },
1771
+ schema: [],
1772
+ });
1773
+ } catch (e) { threw = e; }
1774
+ check("legacy file (no algorithm field) refuses to load — explicit alg required",
1775
+ threw && /MISSING_ALG|missing.*algorithm/i.test(threw.code || threw.message || ""));
1776
+ } finally {
1777
+ await teardownTestDb(tmpDir);
1778
+ }
1779
+ }
1780
+
1781
+ async function testAuditSignRejectsUnsupportedAlgorithm() {
1782
+ // Typo or unsupported alg name surfaces at init time, not as a deeper
1783
+ // "key generation failed" error from nodeCrypto.
1784
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-asbad-"));
1785
+ try {
1786
+ process.env.BLAMEJS_SKIP_NTP_CHECK = "1";
1787
+ process.env.BLAMEJS_AUDIT_SIGNING_MODE = "plaintext";
1788
+ b.cluster._resetForTest();
1789
+ b.audit._resetForTest();
1790
+ b.vault._resetForTest();
1791
+ b.db._resetForTest();
1792
+ await b.vault.init({ dataDir: tmpDir, mode: "plaintext" });
1793
+
1794
+ var threw = null;
1795
+ try {
1796
+ await b.db.init({
1797
+ dataDir: tmpDir,
1798
+ atRest: "plain",
1799
+ auditSigning: { mode: "plaintext", algorithm: "ed25519" }, // not in supported list
1800
+ schema: [],
1801
+ });
1802
+ } catch (e) { threw = e; }
1803
+ check("unsupported algorithm rejected at init",
1804
+ threw && /algorithm must be one of/.test(threw.message));
1805
+ } finally {
1806
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch (_e) {}
1807
+ }
1808
+ }
1809
+
1810
+ async function testCheckpointSign() {
1811
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-ckpt-"));
1812
+ try {
1813
+ await setupTestDb(tmpDir);
1814
+
1815
+ // auditSign module surface
1816
+ check("auditSign namespace present", typeof b.auditSign === "object");
1817
+ check("auditSign.getPublicKey is a function", typeof b.auditSign.getPublicKey === "function");
1818
+ check("auditSign.getPublicKeyFingerprint works",
1819
+ typeof b.auditSign.getPublicKeyFingerprint() === "string" &&
1820
+ b.auditSign.getPublicKeyFingerprint().length === 128);
1821
+
1822
+ // audit-sign keypair file written (wrapped mode is what setupTestDb
1823
+ // configures, matching production posture; sealed file is the
1824
+ // expected on-disk artifact).
1825
+ check("audit-sign.key.sealed file exists in wrapped mode",
1826
+ fs.existsSync(path.join(tmpDir, "audit-sign.key.sealed")));
1827
+
1828
+ // Empty audit_log → checkpoint returns null (nothing to anchor)
1829
+ var emptyResult = await b.audit.checkpoint();
1830
+ check("checkpoint() on empty log returns null", emptyResult === null);
1831
+
1832
+ // Record and checkpoint
1833
+ b.audit.registerNamespace("test");
1834
+ await b.audit.record({ action: "test.event", outcome: "success" });
1835
+ await b.audit.record({ action: "test.event", outcome: "success" });
1836
+ var ckpt = await b.audit.checkpoint();
1837
+ check("checkpoint() returns a checkpoint object", ckpt && typeof ckpt._id === "string");
1838
+ check("checkpoint anchors monotonic counter", typeof ckpt.atMonotonicCounter === "number");
1839
+ check("checkpoint includes pubkey fingerprint",
1840
+ ckpt.publicKeyFingerprint === b.auditSign.getPublicKeyFingerprint());
1841
+
1842
+ // skipIfUnchanged: second call with no new audit activity returns null
1843
+ var skipResult = await b.audit.checkpoint({ skipIfUnchanged: true });
1844
+ check("checkpoint(skipIfUnchanged) on unchanged log returns null", skipResult === null);
1845
+
1846
+ // After more activity, skipIfUnchanged anchors a new checkpoint
1847
+ await b.audit.record({ action: "test.event", outcome: "success" });
1848
+ var freshCkpt = await b.audit.checkpoint({ skipIfUnchanged: true });
1849
+ check("skipIfUnchanged anchors when chain advances", freshCkpt !== null);
1850
+ check("new checkpoint counter > prior checkpoint", freshCkpt.atMonotonicCounter > ckpt.atMonotonicCounter);
1851
+
1852
+ // audit.tip sidecar written
1853
+ var tipPath = path.join(tmpDir, "audit.tip");
1854
+ check("audit.tip sidecar written", fs.existsSync(tipPath));
1855
+ var tip = JSON.parse(fs.readFileSync(tipPath, "utf8"));
1856
+ check("audit.tip records latest counter", tip.atMonotonicCounter === freshCkpt.atMonotonicCounter);
1857
+ } finally {
1858
+ await teardownTestDb(tmpDir);
1859
+ }
1860
+ }
1861
+
1862
+ async function testCheckpointVerify() {
1863
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cverify-"));
1864
+ try {
1865
+ await setupTestDb(tmpDir);
1866
+ b.audit.registerNamespace("test");
1867
+
1868
+ // Empty case
1869
+ var v0 = await b.audit.verifyCheckpoints();
1870
+ check("verifyCheckpoints empty case ok", v0.ok === true && v0.checkpointsVerified === 0);
1871
+
1872
+ // Several events + checkpoints
1873
+ for (var i = 0; i < 5; i++) {
1874
+ await b.audit.record({ action: "test.event", outcome: "success" });
1875
+ await b.audit.checkpoint();
1876
+ }
1877
+ var v1 = await b.audit.verifyCheckpoints();
1878
+ check("verifyCheckpoints ok across multiple anchors", v1.ok === true && v1.checkpointsVerified === 5);
1879
+
1880
+ // Adding more rows then a fresh checkpoint still verifies
1881
+ await b.audit.record({ action: "test.event", outcome: "success" });
1882
+ await b.audit.checkpoint();
1883
+ var v2 = await b.audit.verifyCheckpoints();
1884
+ check("verifyCheckpoints ok after additional checkpoint", v2.ok === true && v2.checkpointsVerified === 6);
1885
+ } finally {
1886
+ await teardownTestDb(tmpDir);
1887
+ }
1888
+ }
1889
+
1890
+ async function testCheckpointTamperDetect() {
1891
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cdetect-"));
1892
+ try {
1893
+ await setupTestDb(tmpDir);
1894
+ b.audit.registerNamespace("test");
1895
+ await b.audit.record({ action: "test.event", outcome: "success" });
1896
+ await b.audit.checkpoint();
1897
+ await b.audit.record({ action: "test.event", outcome: "success" });
1898
+ await b.audit.record({ action: "test.event", outcome: "success" });
1899
+ var anchorCkpt = await b.audit.checkpoint();
1900
+
1901
+ // Tamper with the audit_log row that the checkpoint anchors. Drop the
1902
+ // append-only triggers temporarily, recompute the chain hash so the
1903
+ // per-row chain still verifies (simulating a privileged attacker with
1904
+ // vault key access who's trying to rewrite history). The CHECKPOINT
1905
+ // signature will still mismatch because the original rowHash was signed.
1906
+ b.db.runSql("DROP TRIGGER IF EXISTS no_update_audit_log");
1907
+ var origRow = b.db.prepare("SELECT * FROM audit_log WHERE monotonicCounter = ?").get(anchorCkpt.atMonotonicCounter);
1908
+ // Change something innocuous + recompute rowHash so per-row chain holds
1909
+ var tamperedFields = Object.assign({}, origRow);
1910
+ tamperedFields.outcome = "denied";
1911
+ var nonceBuf = Buffer.isBuffer(origRow.nonce) ? origRow.nonce : Buffer.from(origRow.nonce);
1912
+ var fields = Object.assign({}, tamperedFields);
1913
+ delete fields.prevHash; delete fields.rowHash; delete fields.nonce;
1914
+ var newRowHash = b.auditChain.computeRowHash(origRow.prevHash, fields, nonceBuf);
1915
+ b.db.prepare("UPDATE audit_log SET outcome = ?, rowHash = ? WHERE monotonicCounter = ?")
1916
+ .run("denied", newRowHash, anchorCkpt.atMonotonicCounter);
1917
+ b.db.runSql("CREATE TRIGGER IF NOT EXISTS no_update_audit_log BEFORE UPDATE ON audit_log BEGIN SELECT RAISE(ABORT, 'audit_log is append-only — UPDATE prohibited'); END");
1918
+
1919
+ // Per-row chain may still pass IF attacker also fixed the next row's
1920
+ // prevHash + rowHash recursively. They didn't here; verifyChain might
1921
+ // catch it at the next row. But the CHECKPOINT layer catches it
1922
+ // unconditionally — anchored rowHash no longer matches what's on disk.
1923
+ var ckptResult = await b.audit.verifyCheckpoints();
1924
+ check("checkpoint verify catches anchored-rowHash tampering", ckptResult.ok === false);
1925
+ check("break reason mentions rowHash mismatch",
1926
+ /rowHash mismatch|tampered/i.test(ckptResult.reason || ""));
1927
+ } finally {
1928
+ await teardownTestDb(tmpDir);
1929
+ }
1930
+ }
1931
+
1932
+ async function testRollbackDetection() {
1933
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-rollback-"));
1934
+ try {
1935
+ await setupTestDb(tmpDir);
1936
+ b.audit.registerNamespace("test");
1937
+ for (var i = 0; i < 3; i++) {
1938
+ await b.audit.record({ action: "test.event", outcome: "success" });
1939
+ }
1940
+ await b.audit.checkpoint();
1941
+
1942
+ // audit.tip should now record counter >= 3
1943
+ var tipPath = path.join(tmpDir, "audit.tip");
1944
+ check("audit.tip exists post-checkpoint", fs.existsSync(tipPath));
1945
+ var tip = JSON.parse(fs.readFileSync(tipPath, "utf8"));
1946
+ check("audit.tip records non-zero counter", tip.atMonotonicCounter >= 3);
1947
+
1948
+ // Simulate rollback: write an audit.tip claiming a higher counter than
1949
+ // currently exists in DB. On next boot, db.init() should detect and
1950
+ // refuse — but we can't easily test process.exit() in-process. Verify
1951
+ // the rollback-detection function is wired by inspecting that an
1952
+ // "out of sync" tip would be detected. Use the public surface:
1953
+ // close, write tampered tip, reopen.
1954
+ b.db.close();
1955
+ // CodeQL js/file-system-race: test/ scope only. tipPath is inside the
1956
+ // per-test tmpDir created by setupTestDb (owner-only 0o700); the test
1957
+ // intentionally clobbers it to simulate rollback tampering. No
1958
+ // attacker model in a single-test process; the rule is documented as
1959
+ // a non-finding for test fixtures.
1960
+ fs.writeFileSync(tipPath, JSON.stringify({
1961
+ atMonotonicCounter: 999999,
1962
+ atRowHash: "deadbeef".repeat(16),
1963
+ anchoredAt: Date.now(),
1964
+ checkpointId: "fake",
1965
+ publicKeyFingerprint: "fake",
1966
+ version: 1,
1967
+ }, null, 2));
1968
+
1969
+ // Reopen — should detect rollback and exit. We fork a child to capture
1970
+ // the exit code. The on-disk dataDir is in wrapped/encrypted modes
1971
+ // (setupTestDb's secure default), so the child re-inits in those
1972
+ // same modes; the test passphrase is inherited via env.
1973
+ setTestPassphraseEnv();
1974
+ var spawnSync = require("child_process").spawnSync;
1975
+ var childScript = "var b = require('" + path.resolve("../blamejs/index.js").replace(/\\/g, "/") + "');\n" +
1976
+ "process.env.BLAMEJS_SKIP_NTP_CHECK = '1';\n" +
1977
+ "(async function () {\n" +
1978
+ " await b.vault.init({ dataDir: " + JSON.stringify(tmpDir) + " });\n" +
1979
+ " await b.db.init({ dataDir: " + JSON.stringify(tmpDir) + ", tmpDir: " + JSON.stringify(path.join(tmpDir, "tmpfs")) + ", schema: [] });\n" +
1980
+ "})().catch(function (e) { console.error(e.message); process.exit(99); });\n";
1981
+ var result = spawnSync(process.execPath, ["-e", childScript], { encoding: "utf8" });
1982
+ check("rollback boot exits via the catch handler (code 99)", result.status === 99);
1983
+ check("rollback boot logs detection message", /rollback detected/i.test(result.stderr || ""));
1984
+ } finally {
1985
+ await teardownTestDb(tmpDir);
1986
+ }
1987
+ }
1988
+
1989
+ // ---- run() ----
1990
+
1991
+ async function run() {
1992
+ // cluster-storage (SQL dispatcher)
1993
+ await testClusterStorageLocalDispatch();
1994
+ testClusterStoragePlaceholderize();
1995
+ testClusterStorageResolveTablesIsNoOpInSingleNode();
1996
+ await testClusterStorageClusterDispatch();
1997
+
1998
+ // cluster discovery surface (endpoint + discoveryHandler)
1999
+ testClusterEndpointSingleNode();
2000
+ await testClusterDiscoveryHandlerSingleNode();
2001
+ await testClusterEndpointInitValidation();
2002
+ await testClusterDiscoveryAcquiredLeader();
2003
+
2004
+ // cluster-mode audit-tip fencing (canonical fencing-token guard) +
2005
+ // recursion-safety regression for the handlers.drain bug discovered
2006
+ // while wiring the fence test
2007
+ await testClusterAuditTipFencing();
2008
+ await testClusterAuditFlushNoRecursionHang();
2009
+ await testClusterAuditTipFencedOutErrorSurface();
2010
+
2011
+ // cluster-mode boot-time rollback detection on the audit chain
2012
+ await testClusterAuditTipRollbackHappyPath();
2013
+ await testClusterAuditTipRollbackDetected();
2014
+ await testClusterAuditTipRowHashMismatch();
2015
+
2016
+ // cluster-mode vault-key consistency check
2017
+ await testClusterVaultKeyFirstBootRecords();
2018
+ await testClusterVaultKeyMismatchDetected();
2019
+
2020
+ // cluster-mode sessions: session.* now dispatches through
2021
+ // cluster-storage so writes/reads land in external-db, making the
2022
+ // session store shared across all nodes
2023
+ await testClusterSessionsSharedAcrossNodes();
2024
+
2025
+ // cluster-mode queue: queue-local routes through cluster-storage so
2026
+ // the leader's enqueue/lease/complete operate on the shared
2027
+ // external-db queue — followers don't run lease (gated) but observe
2028
+ // the same state via reads
2029
+ await testClusterQueueJobsSharedAcrossNodes();
2030
+
2031
+ // cluster-mode consent integrity: _blamejs_consent_tip is the
2032
+ // canonical fencing-token-guarded coordination row, updated on
2033
+ // every consent.grant / consent.withdraw, checked at boot for
2034
+ // rollback detection — same protections as audit_log
2035
+ await testClusterConsentTipFencing();
2036
+ await testClusterConsentTipUpdatedOnGrant();
2037
+ await testClusterConsentRollbackDetected();
2038
+
2039
+ // audit chain + verify (now exercises chain-writer transitively)
2040
+ await testAuditChain();
2041
+ await testAuditChainBreak();
2042
+ await testAuditSelfLogging();
2043
+ await testBeginTrace();
2044
+
2045
+ // consent (uses chain-writer)
2046
+ await testConsent();
2047
+
2048
+ // subject rights (uses audit + db)
2049
+ await testSubjectRights();
2050
+
2051
+ // append-only triggers + foreign keys + table metadata
2052
+ await testAppendOnlyTriggers();
2053
+ await testForeignKeys();
2054
+ await testTableMetadata();
2055
+
2056
+ // audit-sign algorithm-agility
2057
+ await testAuditSignDefaultsToSlhDsa();
2058
+ await testAuditSignMlDsaOptIn();
2059
+ await testAuditSignLegacyFileBackcompat();
2060
+ await testAuditSignRejectsUnsupportedAlgorithm();
2061
+
2062
+ // checkpoint sign / verify / tamper / rollback
2063
+ await testCheckpointSign();
2064
+ await testCheckpointVerify();
2065
+ await testCheckpointTamperDetect();
2066
+ await testRollbackDetection();
2067
+ }
2068
+
2069
+ module.exports = {
2070
+ name: "Layer 3 — chain (cluster-storage + audit + consent + subject + checkpoint)",
2071
+ run: run,
2072
+ testClusterStorageLocalDispatch: testClusterStorageLocalDispatch,
2073
+ testClusterStoragePlaceholderize: testClusterStoragePlaceholderize,
2074
+ testClusterStorageResolveTablesIsNoOpInSingleNode: testClusterStorageResolveTablesIsNoOpInSingleNode,
2075
+ testClusterStorageClusterDispatch: testClusterStorageClusterDispatch,
2076
+ testClusterEndpointSingleNode: testClusterEndpointSingleNode,
2077
+ testClusterDiscoveryHandlerSingleNode: testClusterDiscoveryHandlerSingleNode,
2078
+ testClusterEndpointInitValidation: testClusterEndpointInitValidation,
2079
+ testClusterDiscoveryAcquiredLeader: testClusterDiscoveryAcquiredLeader,
2080
+ testClusterAuditTipFencing: testClusterAuditTipFencing,
2081
+ testClusterAuditFlushNoRecursionHang: testClusterAuditFlushNoRecursionHang,
2082
+ testClusterAuditTipFencedOutErrorSurface: testClusterAuditTipFencedOutErrorSurface,
2083
+ testClusterAuditTipRollbackHappyPath: testClusterAuditTipRollbackHappyPath,
2084
+ testClusterAuditTipRollbackDetected: testClusterAuditTipRollbackDetected,
2085
+ testClusterAuditTipRowHashMismatch: testClusterAuditTipRowHashMismatch,
2086
+ testClusterVaultKeyFirstBootRecords: testClusterVaultKeyFirstBootRecords,
2087
+ testClusterVaultKeyMismatchDetected: testClusterVaultKeyMismatchDetected,
2088
+ testClusterSessionsSharedAcrossNodes: testClusterSessionsSharedAcrossNodes,
2089
+ testClusterQueueJobsSharedAcrossNodes: testClusterQueueJobsSharedAcrossNodes,
2090
+ testClusterConsentTipFencing: testClusterConsentTipFencing,
2091
+ testClusterConsentTipUpdatedOnGrant: testClusterConsentTipUpdatedOnGrant,
2092
+ testClusterConsentRollbackDetected: testClusterConsentRollbackDetected,
2093
+ testAuditChain: testAuditChain,
2094
+ testAuditChainBreak: testAuditChainBreak,
2095
+ testAuditSelfLogging: testAuditSelfLogging,
2096
+ testBeginTrace: testBeginTrace,
2097
+ testConsent: testConsent,
2098
+ testSubjectRights: testSubjectRights,
2099
+ testAppendOnlyTriggers: testAppendOnlyTriggers,
2100
+ testForeignKeys: testForeignKeys,
2101
+ testTableMetadata: testTableMetadata,
2102
+ testAuditSignDefaultsToSlhDsa: testAuditSignDefaultsToSlhDsa,
2103
+ testAuditSignMlDsaOptIn: testAuditSignMlDsaOptIn,
2104
+ testAuditSignLegacyFileBackcompat: testAuditSignLegacyFileBackcompat,
2105
+ testAuditSignRejectsUnsupportedAlgorithm: testAuditSignRejectsUnsupportedAlgorithm,
2106
+ testCheckpointSign: testCheckpointSign,
2107
+ testCheckpointVerify: testCheckpointVerify,
2108
+ testCheckpointTamperDetect: testCheckpointTamperDetect,
2109
+ testRollbackDetection: testRollbackDetection,
2110
+ };