@blamejs/blamejs-shop 0.5.12 → 0.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (521) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +632 -416
  4. package/lib/vendor/blamejs/.clusterfuzzlite/Dockerfile +21 -10
  5. package/lib/vendor/blamejs/.clusterfuzzlite/build.sh +30 -9
  6. package/lib/vendor/blamejs/.github/dependabot.yml +8 -0
  7. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  8. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +7 -2
  9. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +7 -2
  10. package/lib/vendor/blamejs/.github/workflows/ci.yml +21 -21
  11. package/lib/vendor/blamejs/.github/workflows/codeql.yml +3 -3
  12. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +4 -4
  13. package/lib/vendor/blamejs/.github/workflows/release-container.yml +7 -7
  14. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +3 -3
  15. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  16. package/lib/vendor/blamejs/.gitignore +2 -0
  17. package/lib/vendor/blamejs/CHANGELOG.md +122 -0
  18. package/lib/vendor/blamejs/NOTICE +26 -1
  19. package/lib/vendor/blamejs/SECURITY.md +1 -1
  20. package/lib/vendor/blamejs/api-snapshot.json +207 -5
  21. package/lib/vendor/blamejs/docker/keycloak/realm-blamejs-test.json +29 -0
  22. package/lib/vendor/blamejs/examples/wiki/DEPLOY.md +1 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/build-app.js +31 -0
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +109 -0
  25. package/lib/vendor/blamejs/examples/wiki/nginx.conf +106 -0
  26. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  27. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +92 -0
  28. package/lib/vendor/blamejs/fuzz/asn1-der.fuzz.js +28 -0
  29. package/lib/vendor/blamejs/fuzz/cms-codec.fuzz.js +17 -0
  30. package/lib/vendor/blamejs/fuzz/link-header.fuzz.js +18 -0
  31. package/lib/vendor/blamejs/index.js +6 -0
  32. package/lib/vendor/blamejs/lib/a2a.js +4 -4
  33. package/lib/vendor/blamejs/lib/agent-idempotency.js +18 -2
  34. package/lib/vendor/blamejs/lib/agent-saga.js +36 -8
  35. package/lib/vendor/blamejs/lib/agent-snapshot.js +63 -6
  36. package/lib/vendor/blamejs/lib/app-shutdown.js +23 -20
  37. package/lib/vendor/blamejs/lib/archive-read.js +8 -0
  38. package/lib/vendor/blamejs/lib/archive-tar.js +12 -2
  39. package/lib/vendor/blamejs/lib/arg-parser.js +49 -5
  40. package/lib/vendor/blamejs/lib/asn1-der.js +12 -0
  41. package/lib/vendor/blamejs/lib/audit-sign.js +47 -1
  42. package/lib/vendor/blamejs/lib/audit.js +71 -8
  43. package/lib/vendor/blamejs/lib/auth/ciba.js +14 -2
  44. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +58 -47
  45. package/lib/vendor/blamejs/lib/auth/jwt.js +34 -0
  46. package/lib/vendor/blamejs/lib/auth/oauth.js +90 -13
  47. package/lib/vendor/blamejs/lib/auth/oid4vci.js +20 -17
  48. package/lib/vendor/blamejs/lib/auth/openid-federation.js +214 -23
  49. package/lib/vendor/blamejs/lib/auth/saml.js +38 -20
  50. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +10 -4
  51. package/lib/vendor/blamejs/lib/backup/bundle.js +13 -3
  52. package/lib/vendor/blamejs/lib/backup/index.js +16 -5
  53. package/lib/vendor/blamejs/lib/backup/manifest.js +18 -5
  54. package/lib/vendor/blamejs/lib/base32.js +21 -0
  55. package/lib/vendor/blamejs/lib/break-glass.js +19 -10
  56. package/lib/vendor/blamejs/lib/bundler.js +5 -1
  57. package/lib/vendor/blamejs/lib/cache-status.js +3 -7
  58. package/lib/vendor/blamejs/lib/calendar.js +21 -1
  59. package/lib/vendor/blamejs/lib/cbor.js +12 -1
  60. package/lib/vendor/blamejs/lib/cert.js +29 -11
  61. package/lib/vendor/blamejs/lib/cli.js +94 -24
  62. package/lib/vendor/blamejs/lib/cloud-events.js +2 -2
  63. package/lib/vendor/blamejs/lib/cluster-provider-db.js +13 -3
  64. package/lib/vendor/blamejs/lib/codepoint-class.js +85 -0
  65. package/lib/vendor/blamejs/lib/compliance-ai-act-prohibited.js +8 -4
  66. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +19 -4
  67. package/lib/vendor/blamejs/lib/compliance-ai-act.js +6 -8
  68. package/lib/vendor/blamejs/lib/content-credentials.js +1 -1
  69. package/lib/vendor/blamejs/lib/content-digest.js +2 -1
  70. package/lib/vendor/blamejs/lib/cookies.js +13 -3
  71. package/lib/vendor/blamejs/lib/cose.js +31 -16
  72. package/lib/vendor/blamejs/lib/crypto-field.js +32 -0
  73. package/lib/vendor/blamejs/lib/crypto-oprf.js +11 -2
  74. package/lib/vendor/blamejs/lib/crypto-xwing.js +22 -4
  75. package/lib/vendor/blamejs/lib/crypto.js +314 -19
  76. package/lib/vendor/blamejs/lib/csp.js +11 -3
  77. package/lib/vendor/blamejs/lib/daemon.js +270 -24
  78. package/lib/vendor/blamejs/lib/dark-patterns.js +5 -2
  79. package/lib/vendor/blamejs/lib/db-declare-view.js +2 -2
  80. package/lib/vendor/blamejs/lib/db-query.js +34 -7
  81. package/lib/vendor/blamejs/lib/db.js +18 -6
  82. package/lib/vendor/blamejs/lib/dbsc.js +17 -0
  83. package/lib/vendor/blamejs/lib/dev.js +21 -2
  84. package/lib/vendor/blamejs/lib/dsr.js +157 -102
  85. package/lib/vendor/blamejs/lib/external-db.js +41 -2
  86. package/lib/vendor/blamejs/lib/file-upload.js +25 -7
  87. package/lib/vendor/blamejs/lib/flag-providers.js +27 -15
  88. package/lib/vendor/blamejs/lib/forms.js +113 -27
  89. package/lib/vendor/blamejs/lib/gate-contract.js +23 -10
  90. package/lib/vendor/blamejs/lib/gdpr-ropa.js +8 -1
  91. package/lib/vendor/blamejs/lib/guard-agent-registry.js +1 -1
  92. package/lib/vendor/blamejs/lib/guard-archive.js +2 -2
  93. package/lib/vendor/blamejs/lib/guard-cidr.js +27 -1
  94. package/lib/vendor/blamejs/lib/guard-graphql.js +30 -11
  95. package/lib/vendor/blamejs/lib/guard-html.js +26 -53
  96. package/lib/vendor/blamejs/lib/guard-image.js +24 -5
  97. package/lib/vendor/blamejs/lib/guard-imap-command.js +10 -2
  98. package/lib/vendor/blamejs/lib/guard-jmap.js +19 -3
  99. package/lib/vendor/blamejs/lib/guard-jwt.js +18 -2
  100. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -2
  101. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +10 -2
  102. package/lib/vendor/blamejs/lib/guard-markdown.js +11 -24
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +18 -2
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +10 -2
  105. package/lib/vendor/blamejs/lib/guard-regex.js +8 -5
  106. package/lib/vendor/blamejs/lib/guard-svg.js +31 -32
  107. package/lib/vendor/blamejs/lib/guard-time.js +1 -1
  108. package/lib/vendor/blamejs/lib/guard-uuid.js +2 -2
  109. package/lib/vendor/blamejs/lib/html-balance.js +3 -3
  110. package/lib/vendor/blamejs/lib/http-client-cache.js +82 -4
  111. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +16 -1
  112. package/lib/vendor/blamejs/lib/http-client.js +39 -7
  113. package/lib/vendor/blamejs/lib/http-message-signature.js +35 -1
  114. package/lib/vendor/blamejs/lib/i18n-messageformat.js +31 -6
  115. package/lib/vendor/blamejs/lib/i18n.js +35 -21
  116. package/lib/vendor/blamejs/lib/incident-report.js +8 -1
  117. package/lib/vendor/blamejs/lib/ip-utils.js +11 -1
  118. package/lib/vendor/blamejs/lib/json-path.js +23 -1
  119. package/lib/vendor/blamejs/lib/jwk.js +20 -3
  120. package/lib/vendor/blamejs/lib/link-header.js +2 -1
  121. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +5 -1
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +5 -1
  123. package/lib/vendor/blamejs/lib/log-stream.js +8 -3
  124. package/lib/vendor/blamejs/lib/mail-auth.js +123 -22
  125. package/lib/vendor/blamejs/lib/mail-bimi.js +1 -1
  126. package/lib/vendor/blamejs/lib/mail-bounce.js +8 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +46 -10
  128. package/lib/vendor/blamejs/lib/mail-dav.js +22 -3
  129. package/lib/vendor/blamejs/lib/mail-dkim.js +96 -30
  130. package/lib/vendor/blamejs/lib/mail-helo.js +6 -1
  131. package/lib/vendor/blamejs/lib/mail-scan.js +23 -16
  132. package/lib/vendor/blamejs/lib/mail-send-deliver.js +34 -8
  133. package/lib/vendor/blamejs/lib/mail-server-imap.js +3 -4
  134. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +7 -11
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +93 -7
  136. package/lib/vendor/blamejs/lib/mail-server-registry.js +8 -2
  137. package/lib/vendor/blamejs/lib/mail.js +15 -5
  138. package/lib/vendor/blamejs/lib/metrics.js +268 -63
  139. package/lib/vendor/blamejs/lib/middleware/age-gate.js +7 -1
  140. package/lib/vendor/blamejs/lib/middleware/asyncapi-serve.js +1 -1
  141. package/lib/vendor/blamejs/lib/middleware/body-parser.js +19 -4
  142. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +5 -9
  143. package/lib/vendor/blamejs/lib/middleware/csp-report.js +40 -8
  144. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +24 -10
  145. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -5
  146. package/lib/vendor/blamejs/lib/middleware/index.js +6 -1
  147. package/lib/vendor/blamejs/lib/middleware/nel.js +1 -1
  148. package/lib/vendor/blamejs/lib/middleware/openapi-serve.js +1 -1
  149. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +12 -1
  150. package/lib/vendor/blamejs/lib/middleware/require-bound-key.js +1 -1
  151. package/lib/vendor/blamejs/lib/middleware/scim-server.js +1 -1
  152. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +6 -2
  153. package/lib/vendor/blamejs/lib/mtls-ca.js +18 -2
  154. package/lib/vendor/blamejs/lib/network-dns-resolver.js +11 -1
  155. package/lib/vendor/blamejs/lib/network-dns.js +21 -2
  156. package/lib/vendor/blamejs/lib/network-tls.js +69 -7
  157. package/lib/vendor/blamejs/lib/nonce-store.js +9 -1
  158. package/lib/vendor/blamejs/lib/object-store/gcs.js +7 -0
  159. package/lib/vendor/blamejs/lib/object-store/sigv4.js +31 -0
  160. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +1 -1
  161. package/lib/vendor/blamejs/lib/outbox.js +1 -1
  162. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +9 -1
  163. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +10 -1
  164. package/lib/vendor/blamejs/lib/permissions.js +6 -3
  165. package/lib/vendor/blamejs/lib/pid-probe.js +55 -0
  166. package/lib/vendor/blamejs/lib/pqc-agent.js +8 -1
  167. package/lib/vendor/blamejs/lib/pqc-software.js +3 -3
  168. package/lib/vendor/blamejs/lib/pubsub.js +20 -9
  169. package/lib/vendor/blamejs/lib/queue-local.js +8 -1
  170. package/lib/vendor/blamejs/lib/queue-redis.js +5 -0
  171. package/lib/vendor/blamejs/lib/redact.js +54 -0
  172. package/lib/vendor/blamejs/lib/restore-bundle.js +10 -2
  173. package/lib/vendor/blamejs/lib/restore.js +19 -0
  174. package/lib/vendor/blamejs/lib/retention.js +12 -4
  175. package/lib/vendor/blamejs/lib/router.js +60 -6
  176. package/lib/vendor/blamejs/lib/safe-buffer.js +69 -0
  177. package/lib/vendor/blamejs/lib/safe-decompress.js +8 -2
  178. package/lib/vendor/blamejs/lib/safe-dns.js +25 -20
  179. package/lib/vendor/blamejs/lib/safe-ical.js +7 -3
  180. package/lib/vendor/blamejs/lib/safe-mime.js +12 -1
  181. package/lib/vendor/blamejs/lib/safe-object.js +80 -0
  182. package/lib/vendor/blamejs/lib/safe-path.js +52 -4
  183. package/lib/vendor/blamejs/lib/safe-redirect.js +10 -2
  184. package/lib/vendor/blamejs/lib/safe-schema.js +4 -1
  185. package/lib/vendor/blamejs/lib/safe-sieve.js +33 -1
  186. package/lib/vendor/blamejs/lib/safe-sql.js +88 -0
  187. package/lib/vendor/blamejs/lib/safe-vcard.js +7 -3
  188. package/lib/vendor/blamejs/lib/scheduler.js +8 -1
  189. package/lib/vendor/blamejs/lib/security-assert.js +6 -6
  190. package/lib/vendor/blamejs/lib/self-update-standalone-verifier.js +74 -27
  191. package/lib/vendor/blamejs/lib/self-update.js +517 -87
  192. package/lib/vendor/blamejs/lib/server-timing.js +2 -4
  193. package/lib/vendor/blamejs/lib/session.js +34 -12
  194. package/lib/vendor/blamejs/lib/sql.js +15 -1
  195. package/lib/vendor/blamejs/lib/ssrf-guard.js +52 -0
  196. package/lib/vendor/blamejs/lib/static.js +55 -13
  197. package/lib/vendor/blamejs/lib/storage.js +8 -2
  198. package/lib/vendor/blamejs/lib/subject.js +6 -1
  199. package/lib/vendor/blamejs/lib/tenant-quota.js +52 -13
  200. package/lib/vendor/blamejs/lib/tls-exporter.js +3 -3
  201. package/lib/vendor/blamejs/lib/tsa.js +34 -13
  202. package/lib/vendor/blamejs/lib/uri-template.js +8 -1
  203. package/lib/vendor/blamejs/lib/vault/index.js +13 -0
  204. package/lib/vendor/blamejs/lib/vc.js +44 -5
  205. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +26 -26
  206. package/lib/vendor/blamejs/lib/vendor/noble-ciphers.cjs +792 -1
  207. package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +3443 -1
  208. package/lib/vendor/blamejs/lib/vendor/noble-post-quantum.cjs +2737 -1
  209. package/lib/vendor/blamejs/lib/vendor/pki.cjs +39550 -13
  210. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.dat +55 -53
  211. package/lib/vendor/blamejs/lib/vendor/public-suffix-list.data.js +5551 -5554
  212. package/lib/vendor/blamejs/lib/vendor/simplewebauthn-server.cjs +22459 -32
  213. package/lib/vendor/blamejs/lib/watcher.js +89 -17
  214. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +25 -3
  215. package/lib/vendor/blamejs/lib/webhook.js +12 -2
  216. package/lib/vendor/blamejs/lib/ws-client.js +32 -1
  217. package/lib/vendor/blamejs/lib/xml-c14n.js +29 -1
  218. package/lib/vendor/blamejs/oss-fuzz/projects/blamejs/Dockerfile +1 -1
  219. package/lib/vendor/blamejs/package-lock.json +2 -2
  220. package/lib/vendor/blamejs/package.json +1 -1
  221. package/lib/vendor/blamejs/release-notes/v0.16.x.json +1462 -0
  222. package/lib/vendor/blamejs/release-notes/v0.17.0.json +31 -0
  223. package/lib/vendor/blamejs/release-notes/v0.17.1.json +31 -0
  224. package/lib/vendor/blamejs/release-notes/v0.17.10.json +30 -0
  225. package/lib/vendor/blamejs/release-notes/v0.17.11.json +22 -0
  226. package/lib/vendor/blamejs/release-notes/v0.17.12.json +18 -0
  227. package/lib/vendor/blamejs/release-notes/v0.17.13.json +77 -0
  228. package/lib/vendor/blamejs/release-notes/v0.17.14.json +40 -0
  229. package/lib/vendor/blamejs/release-notes/v0.17.15.json +18 -0
  230. package/lib/vendor/blamejs/release-notes/v0.17.16.json +27 -0
  231. package/lib/vendor/blamejs/release-notes/v0.17.17.json +31 -0
  232. package/lib/vendor/blamejs/release-notes/v0.17.18.json +18 -0
  233. package/lib/vendor/blamejs/release-notes/v0.17.19.json +18 -0
  234. package/lib/vendor/blamejs/release-notes/v0.17.2.json +26 -0
  235. package/lib/vendor/blamejs/release-notes/v0.17.20.json +43 -0
  236. package/lib/vendor/blamejs/release-notes/v0.17.21.json +26 -0
  237. package/lib/vendor/blamejs/release-notes/v0.17.22.json +18 -0
  238. package/lib/vendor/blamejs/release-notes/v0.17.3.json +43 -0
  239. package/lib/vendor/blamejs/release-notes/v0.17.4.json +35 -0
  240. package/lib/vendor/blamejs/release-notes/v0.17.5.json +26 -0
  241. package/lib/vendor/blamejs/release-notes/v0.17.6.json +26 -0
  242. package/lib/vendor/blamejs/release-notes/v0.17.7.json +35 -0
  243. package/lib/vendor/blamejs/release-notes/v0.17.8.json +22 -0
  244. package/lib/vendor/blamejs/release-notes/v0.17.9.json +26 -0
  245. package/lib/vendor/blamejs/scripts/validate-source-comment-blocks.js +4 -0
  246. package/lib/vendor/blamejs/scripts/vendor-update.sh +293 -9
  247. package/lib/vendor/blamejs/socket.yml +94 -0
  248. package/lib/vendor/blamejs/test/00-primitives.js +605 -0
  249. package/lib/vendor/blamejs/test/helpers/drivers.js +12 -9
  250. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +90 -1
  251. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +122 -1
  252. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +30 -0
  253. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +29 -0
  254. package/lib/vendor/blamejs/test/integration/dsr-cluster-mysql.test.js +479 -0
  255. package/lib/vendor/blamejs/test/integration/dsr-cluster-pg.test.js +487 -0
  256. package/lib/vendor/blamejs/test/integration/federation-auth.test.js +313 -5
  257. package/lib/vendor/blamejs/test/integration/mail-dkim.test.js +80 -0
  258. package/lib/vendor/blamejs/test/integration/openid-federation-chain.test.js +275 -0
  259. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +96 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/a2a-tasks.test.js +401 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/acme.test.js +1649 -2
  262. package/lib/vendor/blamejs/test/layer-0-primitives/age-gate.test.js +33 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/agent-idempotency.test.js +0 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/agent-saga.test.js +60 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/agent-snapshot.test.js +524 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/api-encrypt.test.js +891 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/app-shutdown.test.js +128 -1
  268. package/lib/vendor/blamejs/test/layer-0-primitives/archive-adapters.test.js +271 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/archive-read.test.js +628 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/archive-tar-read.test.js +0 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/archive-wrap.test.js +227 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/arg-parser.test.js +15 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/asn1-der.test.js +73 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file.test.js +114 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +141 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/audit-tools.test.js +624 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/audit.test.js +769 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/auth-jwt-defenses.test.js +436 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth.test.js +1697 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oid4vp.test.js +495 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/auth-password.test.js +500 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml.test.js +1809 -0
  283. package/lib/vendor/blamejs/test/layer-0-primitives/auth-status-list.test.js +243 -1
  284. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index.test.js +2226 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/backup-manifest-signature.test.js +183 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/base32.test.js +105 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +693 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/cache.test.js +603 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/calendar.test.js +557 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/case-insensitive-security-token-guard.test.js +214 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/cbor.test.js +25 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/cert.test.js +843 -6
  293. package/lib/vendor/blamejs/test/layer-0-primitives/ciba-authreqid-binding.test.js +77 -2
  294. package/lib/vendor/blamejs/test/layer-0-primitives/ciba.test.js +866 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/clear-site-data.test.js +18 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/cli-erase.test.js +19 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/cli.test.js +2790 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/cluster-lease-renewal-ttl.test.js +114 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/cluster.test.js +1032 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/cms-codec.test.js +575 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +739 -1
  302. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +8 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-ai-act.test.js +194 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-lifecycle-proto-key.test.js +104 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/compliance-sanctions.test.js +254 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials.test.js +613 -3
  307. package/lib/vendor/blamejs/test/layer-0-primitives/cookies.test.js +140 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/cose.test.js +407 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-adversarial.test.js +352 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +32 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field.test.js +575 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-files-parallel.test.js +10 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +24 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +17 -0
  315. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-spki-pin.test.js +183 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-xwing.test.js +48 -0
  317. package/lib/vendor/blamejs/test/layer-0-primitives/crypto.test.js +345 -0
  318. package/lib/vendor/blamejs/test/layer-0-primitives/csp-report.test.js +58 -0
  319. package/lib/vendor/blamejs/test/layer-0-primitives/csv.test.js +48 -0
  320. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +459 -1
  321. package/lib/vendor/blamejs/test/layer-0-primitives/dark-patterns.test.js +19 -0
  322. package/lib/vendor/blamejs/test/layer-0-primitives/db-query.test.js +1019 -0
  323. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +77 -0
  324. package/lib/vendor/blamejs/test/layer-0-primitives/db.test.js +1621 -0
  325. package/lib/vendor/blamejs/test/layer-0-primitives/ddl-change-control.test.js +462 -3
  326. package/lib/vendor/blamejs/test/layer-0-primitives/dnssec.test.js +323 -0
  327. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-verify.test.js +562 -0
  328. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +901 -1
  329. package/lib/vendor/blamejs/test/layer-0-primitives/dual-control.test.js +249 -0
  330. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +561 -0
  331. package/lib/vendor/blamejs/test/layer-0-primitives/external-db.test.js +1214 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/fal.test.js +21 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/fedcm-dbsc.test.js +46 -20
  334. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +147 -3
  335. package/lib/vendor/blamejs/test/layer-0-primitives/fido-mds3.test.js +907 -38
  336. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +29 -0
  337. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload.test.js +1135 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +30 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/forms.test.js +747 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract.test.js +1855 -0
  341. package/lib/vendor/blamejs/test/layer-0-primitives/gdpr-ropa.test.js +30 -0
  342. package/lib/vendor/blamejs/test/layer-0-primitives/guard-archive.test.js +86 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/guard-auth.test.js +117 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/guard-cidr.test.js +151 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/guard-domain.test.js +422 -0
  346. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +424 -0
  347. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-gate-disposition-coverage.test.js → guard-gate-disposition.test.js} +1 -1
  348. package/lib/vendor/blamejs/test/layer-0-primitives/guard-graphql.test.js +340 -0
  349. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +29 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/guard-idempotency-key.test.js +28 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +519 -45
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jmap.test.js +51 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jsonpath.test.js +66 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-jwt.test.js +436 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +25 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +16 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-mime.test.js +86 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-oauth.test.js +140 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +80 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +27 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-regex.test.js +99 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-shell.test.js +76 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/{guard-sql-coverage.test.js → guard-sql.test.js} +3 -3
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +524 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-template.test.js +71 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/guard-time.test.js +92 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/guard-uuid.test.js +86 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/html-balance.test.js +38 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache-authorization.test.js +347 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-cache.test.js +908 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/http-client.test.js +2874 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/http-message-signature.test.js +643 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/i18n-messageformat.test.js +38 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +1153 -1
  376. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +494 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +30 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/jsdoc-example-execution.test.js +177 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/json-path.test.js +103 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/json-schema.test.js +214 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/jwk.test.js +41 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/jwt-external.test.js +276 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/keychain.test.js +0 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/log-stream.test.js +241 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/log.test.js +106 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/mail-agent.test.js +441 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +2136 -4
  388. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bimi.test.js +759 -12
  389. package/lib/vendor/blamejs/test/layer-0-primitives/mail-bounce.test.js +811 -1
  390. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp-experimental.test.js +401 -3
  391. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-pgp.test.js +751 -8
  392. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto-smime.test.js +864 -0
  393. package/lib/vendor/blamejs/test/layer-0-primitives/mail-crypto.test.js +110 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dav.test.js +830 -1
  395. package/lib/vendor/blamejs/test/layer-0-primitives/mail-deploy.test.js +635 -86
  396. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +818 -0
  397. package/lib/vendor/blamejs/test/layer-0-primitives/mail-helo.test.js +27 -0
  398. package/lib/vendor/blamejs/test/layer-0-primitives/mail-scan.test.js +199 -0
  399. package/lib/vendor/blamejs/test/layer-0-primitives/mail-send-deliver.test.js +686 -2
  400. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-imap.test.js +778 -0
  401. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +1438 -0
  402. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-managesieve.test.js +449 -6
  403. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +773 -2
  404. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-pop3.test.js +623 -3
  405. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-rate-limit.test.js +55 -0
  406. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-registry.test.js +13 -0
  407. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-submission.test.js +877 -1
  408. package/lib/vendor/blamejs/test/layer-0-primitives/mail-sieve.test.js +326 -0
  409. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store-fts.test.js +55 -0
  410. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +242 -0
  411. package/lib/vendor/blamejs/test/layer-0-primitives/mail.test.js +1596 -2
  412. package/lib/vendor/blamejs/test/layer-0-primitives/mcp.test.js +440 -4
  413. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-snapshot.test.js +89 -0
  414. package/lib/vendor/blamejs/test/layer-0-primitives/metrics.test.js +1230 -0
  415. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-assetlinks.test.js +113 -0
  416. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-body-parser.test.js +1169 -0
  417. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-bot-disclose.test.js +123 -0
  418. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-cookies.test.js +108 -0
  419. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-gpc.test.js +121 -0
  420. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-headers.test.js +163 -0
  421. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-host-allowlist.test.js +154 -0
  422. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-require-content-type.test.js +127 -0
  423. package/lib/vendor/blamejs/test/layer-0-primitives/{middleware-tus-upload-coverage.test.js → middleware-tus-upload.test.js} +45 -0
  424. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-web-app-manifest.test.js +132 -0
  425. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-crl-fingerprint-only.test.js +92 -0
  426. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns-resolver.test.js +65 -0
  427. package/lib/vendor/blamejs/test/layer-0-primitives/network-dns.test.js +1727 -1
  428. package/lib/vendor/blamejs/test/layer-0-primitives/network-nts.test.js +699 -0
  429. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy.test.js +1181 -0
  430. package/lib/vendor/blamejs/test/layer-0-primitives/network-tls.test.js +1876 -3
  431. package/lib/vendor/blamejs/test/layer-0-primitives/network.test.js +32 -0
  432. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-enforce-replay-nonboolean.test.js +81 -0
  433. package/lib/vendor/blamejs/test/layer-0-primitives/ntp-check.test.js +122 -0
  434. package/lib/vendor/blamejs/test/layer-0-primitives/observability-tracing.test.js +378 -0
  435. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +77 -0
  436. package/lib/vendor/blamejs/test/layer-0-primitives/oid4vci.test.js +1016 -0
  437. package/lib/vendor/blamejs/test/layer-0-primitives/openid-federation.test.js +946 -0
  438. package/lib/vendor/blamejs/test/layer-0-primitives/outbox.test.js +818 -0
  439. package/lib/vendor/blamejs/test/layer-0-primitives/own-property-membership-guards.test.js +109 -0
  440. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-toml.test.js +543 -0
  441. package/lib/vendor/blamejs/test/layer-0-primitives/{parsers-safe-yaml-coverage.test.js → parsers-safe-yaml.test.js} +2 -2
  442. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +73 -0
  443. package/lib/vendor/blamejs/test/layer-0-primitives/passkey.test.js +649 -0
  444. package/lib/vendor/blamejs/test/layer-0-primitives/permissions.test.js +524 -0
  445. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +22 -0
  446. package/lib/vendor/blamejs/test/layer-0-primitives/pubsub.test.js +295 -0
  447. package/lib/vendor/blamejs/test/layer-0-primitives/queue-flow-repeat.test.js +36 -0
  448. package/lib/vendor/blamejs/test/layer-0-primitives/queue.test.js +83 -0
  449. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-xff-spoofing.test.js +34 -0
  450. package/lib/vendor/blamejs/test/layer-0-primitives/redact.test.js +1031 -0
  451. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +94 -0
  452. package/lib/vendor/blamejs/test/layer-0-primitives/require-bound-key.test.js +401 -0
  453. package/lib/vendor/blamejs/test/layer-0-primitives/restore-empty-manifest-wipe.test.js +154 -0
  454. package/lib/vendor/blamejs/test/layer-0-primitives/retention.test.js +600 -0
  455. package/lib/vendor/blamejs/test/layer-0-primitives/router-host-path-injection.test.js +231 -0
  456. package/lib/vendor/blamejs/test/layer-0-primitives/router-tls0rtt.test.js +21 -0
  457. package/lib/vendor/blamejs/test/layer-0-primitives/router.test.js +1277 -0
  458. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async.test.js +133 -0
  459. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +14 -0
  460. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer.test.js +80 -0
  461. package/lib/vendor/blamejs/test/layer-0-primitives/safe-decompress.test.js +28 -0
  462. package/lib/vendor/blamejs/test/layer-0-primitives/safe-dns.test.js +245 -0
  463. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ical.test.js +32 -0
  464. package/lib/vendor/blamejs/test/layer-0-primitives/safe-ini.test.js +376 -0
  465. package/lib/vendor/blamejs/test/layer-0-primitives/safe-json.test.js +175 -0
  466. package/lib/vendor/blamejs/test/layer-0-primitives/safe-mime.test.js +518 -0
  467. package/lib/vendor/blamejs/test/layer-0-primitives/safe-object.test.js +62 -0
  468. package/lib/vendor/blamejs/test/layer-0-primitives/safe-path.test.js +30 -0
  469. package/lib/vendor/blamejs/test/layer-0-primitives/safe-schema.test.js +104 -0
  470. package/lib/vendor/blamejs/test/layer-0-primitives/safe-sql.test.js +142 -0
  471. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url.test.js +112 -0
  472. package/lib/vendor/blamejs/test/layer-0-primitives/safe-vcard.test.js +26 -0
  473. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler.test.js +157 -0
  474. package/lib/vendor/blamejs/test/layer-0-primitives/scim-server.test.js +396 -0
  475. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +930 -0
  476. package/lib/vendor/blamejs/test/layer-0-primitives/security-assert.test.js +755 -82
  477. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +1053 -0
  478. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +200 -0
  479. package/lib/vendor/blamejs/test/layer-0-primitives/session-strict-binding-missing-failclosed.test.js +110 -0
  480. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +636 -0
  481. package/lib/vendor/blamejs/test/layer-0-primitives/sql-offset-without-limit.test.js +94 -0
  482. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +1190 -0
  483. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +21 -0
  484. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +850 -0
  485. package/lib/vendor/blamejs/test/layer-0-primitives/storage-presigned-url.test.js +146 -0
  486. package/lib/vendor/blamejs/test/layer-0-primitives/storage.test.js +621 -0
  487. package/lib/vendor/blamejs/test/layer-0-primitives/subject.test.js +47 -0
  488. package/lib/vendor/blamejs/test/layer-0-primitives/template.test.js +582 -0
  489. package/lib/vendor/blamejs/test/layer-0-primitives/tenant-quota.test.js +587 -25
  490. package/lib/vendor/blamejs/test/layer-0-primitives/time.test.js +11 -0
  491. package/lib/vendor/blamejs/test/layer-0-primitives/tsa.test.js +524 -63
  492. package/lib/vendor/blamejs/test/layer-0-primitives/uri-template.test.js +27 -0
  493. package/lib/vendor/blamejs/test/layer-0-primitives/vault-rotate.test.js +866 -0
  494. package/lib/vendor/blamejs/test/layer-0-primitives/vault.test.js +74 -0
  495. package/lib/vendor/blamejs/test/layer-0-primitives/vc.test.js +215 -0
  496. package/lib/vendor/blamejs/test/layer-0-primitives/watcher.test.js +550 -0
  497. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +388 -0
  498. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +262 -0
  499. package/lib/vendor/blamejs/test/layer-0-primitives/websocket.test.js +1294 -0
  500. package/lib/vendor/blamejs/test/layer-0-primitives/ws-client.test.js +629 -0
  501. package/lib/vendor/blamejs/test/layer-0-primitives/xml-c14n-attr-normalization.test.js +164 -0
  502. package/lib/vendor/blamejs/test/smoke.js +2 -0
  503. package/package.json +1 -1
  504. package/lib/vendor/blamejs/release-notes/v0.16.0.json +0 -44
  505. package/lib/vendor/blamejs/release-notes/v0.16.1.json +0 -36
  506. package/lib/vendor/blamejs/release-notes/v0.16.2.json +0 -71
  507. package/lib/vendor/blamejs/release-notes/v0.16.3.json +0 -71
  508. package/lib/vendor/blamejs/test/layer-0-primitives/acme-coverage.test.js +0 -441
  509. package/lib/vendor/blamejs/test/layer-0-primitives/auth-oauth-coverage.test.js +0 -482
  510. package/lib/vendor/blamejs/test/layer-0-primitives/auth-saml-coverage.test.js +0 -671
  511. package/lib/vendor/blamejs/test/layer-0-primitives/backup-index-coverage.test.js +0 -690
  512. package/lib/vendor/blamejs/test/layer-0-primitives/cli-coverage.test.js +0 -238
  513. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +0 -319
  514. package/lib/vendor/blamejs/test/layer-0-primitives/keychain-coverage.test.js +0 -0
  515. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth-coverage.test.js +0 -437
  516. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +0 -443
  517. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +0 -395
  518. package/lib/vendor/blamejs/test/layer-0-primitives/network-smtp-policy-coverage.test.js +0 -565
  519. package/lib/vendor/blamejs/test/layer-0-primitives/router-coverage.test.js +0 -592
  520. package/lib/vendor/blamejs/test/layer-0-primitives/sql-coverage.test.js +0 -422
  521. package/lib/vendor/blamejs/test/layer-0-primitives/test-coverage.test.js +0 -573
@@ -0,0 +1,1621 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) blamejs contributors
3
+ "use strict";
4
+ /**
5
+ * db — error / defensive / adversarial branch coverage for
6
+ * lib/db.js driven through the public b.db surface. Focus is the
7
+ * non-happy-path: bad-init opts, reserved-table collisions,
8
+ * personal-data-category validation, exportCsv / transaction / stream
9
+ * / vacuum / worm / dual-control / eraseHard / purge validation
10
+ * throws, the tmpfs storage-headroom write gate (fault-injected
11
+ * statfs), the not-initialized guard across entry points, and the
12
+ * close/idempotency + generation-counter seams.
13
+ */
14
+
15
+ var helpers = require("../helpers");
16
+ var b = helpers.b;
17
+ var check = helpers.check;
18
+ var fs = helpers.fs;
19
+ var os = helpers.os;
20
+ var path = helpers.path;
21
+
22
+ var C = b.constants;
23
+
24
+ // --- shared local fixtures ------------------------------------------------
25
+
26
+ function _mkTmp(prefix) {
27
+ return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
28
+ }
29
+
30
+ async function _freshVault(tmpDir) {
31
+ process.env.BLAMEJS_SKIP_NTP_CHECK = "1";
32
+ process.env.BLAMEJS_VAULT_PASSPHRASE = "test-passphrase-suite";
33
+ process.env.BLAMEJS_AUDIT_SIGNING_PASSPHRASE = "test-passphrase-suite";
34
+ b.cluster._resetForTest();
35
+ b.audit._resetForTest();
36
+ b.vault._resetForTest();
37
+ b.db._resetForTest();
38
+ await b.vault.init({ dataDir: tmpDir, mode: "plaintext" });
39
+ }
40
+
41
+ // Plain-mode db (fast; no tmpfs, no encryption envelope). frameworkTables
42
+ // default ON unless the caller overrides via `extra`.
43
+ async function _plainInit(tmpDir, schema, extra) {
44
+ await _freshVault(tmpDir);
45
+ var opts = { dataDir: tmpDir, atRest: "plain", schema: schema || [] };
46
+ if (extra) Object.assign(opts, extra);
47
+ await b.db.init(opts);
48
+ }
49
+
50
+ function _teardownPlain(tmpDir) {
51
+ try { b.db.close(); } catch (_e) { /* may already be closed */ }
52
+ b.db._resetForTest();
53
+ b.vault._resetForTest();
54
+ b.cluster._resetForTest();
55
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch (_e) { /* best effort */ }
56
+ }
57
+
58
+ // Return the thrown error (or null) for a sync-or-async thunk.
59
+ async function _catch(thunk) {
60
+ try { await thunk(); return null; }
61
+ catch (e) { return e; }
62
+ }
63
+
64
+ // --- init() argument validation (no db opened) ----------------------------
65
+
66
+ async function testInitArgValidation() {
67
+ // Ensure a clean not-initialized state so the `if (initialized) return`
68
+ // early-out doesn't swallow these throws.
69
+ b.cluster._resetForTest();
70
+ b.audit._resetForTest();
71
+ b.vault._resetForTest();
72
+ b.db._resetForTest();
73
+ var tmpDir = _mkTmp("db-cov-argv-");
74
+ try {
75
+ var e1 = await _catch(function () { return b.db.init(); });
76
+ check("init() with no opts throws db/bad-init", e1 && e1.code === "db/bad-init");
77
+
78
+ var e2 = await _catch(function () { return b.db.init({}); });
79
+ check("init({}) missing dataDir throws db/bad-init", e2 && e2.code === "db/bad-init");
80
+
81
+ var e3 = await _catch(function () { return b.db.init({ dataDir: tmpDir, schema: "notarray" }); });
82
+ check("init non-array schema throws db/bad-init", e3 && e3.code === "db/bad-init");
83
+
84
+ var e4 = await _catch(function () { return b.db.init({ dataDir: tmpDir, schema: [], atRest: "weird" }); });
85
+ check("init bad atRest throws db/bad-at-rest", e4 && e4.code === "db/bad-at-rest");
86
+
87
+ var e5 = await _catch(function () { return b.db.init({ dataDir: tmpDir, schema: [], atRest: "plain", streamLimit: -1 }); });
88
+ check("init negative streamLimit throws", e5 !== null);
89
+
90
+ var e6 = await _catch(function () { return b.db.init({ dataDir: tmpDir, schema: [], atRest: "plain", streamLimit: 1.5 }); });
91
+ check("init non-integer streamLimit throws", e6 !== null);
92
+
93
+ var e7 = await _catch(function () { return b.db.init({ dataDir: tmpDir, schema: [], atRest: "plain", columnGate: "bogus" }); });
94
+ check("init bad columnGate throws db/bad-init", e7 && e7.code === "db/bad-init");
95
+
96
+ // db was never opened by any of these — still not initialized.
97
+ var e8 = await _catch(function () { return b.db.from("x"); });
98
+ check("after failed inits, from() reports not-initialized", e8 && e8.code === "db/not-initialized");
99
+ } finally {
100
+ b.db._resetForTest();
101
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch (_e) { /* best effort */ }
102
+ }
103
+ }
104
+
105
+ // --- not-initialized guard across the public entry points -----------------
106
+
107
+ async function testNotInitializedGuard() {
108
+ b.db._resetForTest();
109
+ var errs = {
110
+ from: await _catch(function () { return b.db.from("t"); }),
111
+ prepare: await _catch(function () { return b.db.prepare("SELECT 1"); }),
112
+ stream: await _catch(function () { return b.db.stream("SELECT 1"); }),
113
+ transaction: await _catch(function () { return b.db.transaction(function () {}); }),
114
+ hashFor: await _catch(function () { return b.db.hashFor("t", "f", "v"); }),
115
+ snapshot: await _catch(function () { return b.db.snapshot(); }),
116
+ exportCsv: await _catch(function () { return b.db.exportCsv({ table: "t" }); }),
117
+ eraseHard: await _catch(function () { return b.db.eraseHard("t", "r", { reason: "x" }); }),
118
+ declareWorm: await _catch(function () { return b.db.declareWorm({ tables: ["t"] }); }),
119
+ integrityCheck: await _catch(function () { return b.db.integrityCheck(); }),
120
+ runSql: await _catch(function () { return b.db.runSql("SELECT 1"); }),
121
+ };
122
+ Object.keys(errs).forEach(function (k) {
123
+ check("not-initialized guard fires for " + k,
124
+ errs[k] && errs[k].code === "db/not-initialized");
125
+ });
126
+ // Accessors are safe pre-init and read null-ish state.
127
+ check("getMode() null before init", b.db.getMode() === null);
128
+ check("getDbPath() null before init", b.db.getDbPath() === null);
129
+ check("getDataResidency() null before init", b.db.getDataResidency() === null);
130
+ }
131
+
132
+ // --- reserved framework table-name collisions -----------------------------
133
+
134
+ async function testReservedTableNames() {
135
+ var tmpDir = _mkTmp("db-cov-reserved-");
136
+ try {
137
+ var e1 = await _catch(function () {
138
+ return _plainInit(tmpDir, [{ name: "audit_log", columns: { _id: "TEXT PRIMARY KEY" } }]);
139
+ });
140
+ check("schema colliding with audit_log throws db/reserved-table-name",
141
+ e1 && e1.code === "db/reserved-table-name");
142
+ b.db._resetForTest();
143
+
144
+ var e2 = await _catch(function () {
145
+ return _plainInit(tmpDir, [{ name: "_blamejs_custom", columns: { _id: "TEXT PRIMARY KEY" } }]);
146
+ });
147
+ check("schema with _blamejs_ prefix throws db/reserved-table-name",
148
+ e2 && e2.code === "db/reserved-table-name");
149
+ b.db._resetForTest();
150
+
151
+ // Under frameworkTables:false the operator MAY own an audit_log.
152
+ await _plainInit(tmpDir, [{ name: "audit_log", columns: { _id: "TEXT PRIMARY KEY" } }],
153
+ { frameworkTables: false, auditSigning: false });
154
+ check("frameworkTables:false lets operator name a table audit_log",
155
+ typeof b.db.from === "function");
156
+ } finally {
157
+ _teardownPlain(tmpDir);
158
+ }
159
+ }
160
+
161
+ // --- personalDataCategories validation ------------------------------------
162
+
163
+ async function testPersonalDataCategories() {
164
+ var tmpDir = _mkTmp("db-cov-pdc-");
165
+ try {
166
+ var badShape = await _catch(function () {
167
+ return _plainInit(tmpDir, [{
168
+ name: "people", columns: { _id: "TEXT PRIMARY KEY", uid: "TEXT" },
169
+ subjectField: "uid", personalDataCategories: "not-an-object",
170
+ }]);
171
+ });
172
+ check("personalDataCategories non-object throws db/bad-personal-data-categories",
173
+ badShape && badShape.code === "db/bad-personal-data-categories");
174
+ b.db._resetForTest();
175
+
176
+ var badVal = await _catch(function () {
177
+ return _plainInit(tmpDir, [{
178
+ name: "people", columns: { _id: "TEXT PRIMARY KEY", uid: "TEXT" },
179
+ subjectField: "uid", personalDataCategories: { uid: 123 },
180
+ }]);
181
+ });
182
+ check("personalDataCategories non-string value throws db/bad-personal-data-category",
183
+ badVal && badVal.code === "db/bad-personal-data-category");
184
+ b.db._resetForTest();
185
+
186
+ // Known + unknown vocabulary both accepted; unknown emits a warning
187
+ // audit (drop-silent) and init still succeeds.
188
+ await _plainInit(tmpDir, [{
189
+ name: "people", columns: { _id: "TEXT PRIMARY KEY", uid: "TEXT" },
190
+ subjectField: "uid",
191
+ personalDataCategories: { uid: "email", extra: "totally-unknown-category" },
192
+ }]);
193
+ check("init succeeds with a mix of known + unknown data categories",
194
+ b.db.getTableMetadata("people").subjectField === "uid");
195
+ } finally {
196
+ _teardownPlain(tmpDir);
197
+ }
198
+ }
199
+
200
+ // --- getTableMetadata dispatch + accessors --------------------------------
201
+
202
+ async function testMetadataAndAccessors() {
203
+ var tmpDir = _mkTmp("db-cov-meta-");
204
+ try {
205
+ await helpers.setupTestDb(tmpDir, [{
206
+ name: "orders",
207
+ columns: { _id: "TEXT PRIMARY KEY", note: "TEXT", total: "INTEGER NOT NULL", totalHash: "TEXT" },
208
+ sealedFields: ["note"],
209
+ derivedHashes: { totalHash: { from: "total" } },
210
+ }, {
211
+ // A table declaring a structured foreignKeys array — its metadata
212
+ // snapshot must carry the FK relationship through for RoPA / tooling.
213
+ name: "line_items",
214
+ columns: { _id: "TEXT PRIMARY KEY", orderId: "TEXT NOT NULL", qty: "INTEGER NOT NULL" },
215
+ foreignKeys: [{ column: "orderId", references: "orders._id", onDelete: "CASCADE" }],
216
+ }]);
217
+
218
+ check("getMode() returns encrypted", b.db.getMode() === "encrypted");
219
+ check("getDbPath() is a string path", typeof b.db.getDbPath() === "string");
220
+ check("getStreamLimit() default is 1_000_000", b.db.getStreamLimit() === 1000000);
221
+ check("getDataResidency() null when unset", b.db.getDataResidency() === null);
222
+
223
+ check("getDeclaredColumns known table lists _id",
224
+ b.db.getDeclaredColumns("orders").indexOf("_id") !== -1);
225
+ check("getDeclaredColumns unknown table returns null",
226
+ b.db.getDeclaredColumns("nope") === null);
227
+
228
+ check("getTableMetadata() no-arg returns a snapshot object",
229
+ typeof b.db.getTableMetadata() === "object" && !!b.db.getTableMetadata().orders);
230
+ check("getTableMetadata(string) returns the table meta",
231
+ b.db.getTableMetadata("orders").sealedFields.indexOf("note") !== -1);
232
+ check("getTableMetadata(unknown-string) returns null",
233
+ b.db.getTableMetadata("nope") === null);
234
+ check("getTableMetadata(non-object non-string) returns null",
235
+ b.db.getTableMetadata(123) === null);
236
+ check("getTableMetadata({ table: unknown }) returns null",
237
+ b.db.getTableMetadata({ table: "nope" }) === null);
238
+
239
+ // Object form without a `format` key falls back to the native blamejs
240
+ // snapshot (the `format || "blamejs"` default).
241
+ var noFmt = b.db.getTableMetadata({ table: "orders" });
242
+ check("getTableMetadata({ table }) with no format returns the native snapshot",
243
+ noFmt && Array.isArray(noFmt.sealedFields) && noFmt.columns._id === "TEXT PRIMARY KEY");
244
+
245
+ // A declared foreignKeys array rides through into the metadata snapshot.
246
+ var fkMeta = b.db.getTableMetadata("line_items");
247
+ check("getTableMetadata surfaces a declared foreignKeys relationship",
248
+ Array.isArray(fkMeta.foreignKeys) && fkMeta.foreignKeys.length === 1 &&
249
+ fkMeta.foreignKeys[0].column === "orderId" &&
250
+ fkMeta.foreignKeys[0].references === "orders._id");
251
+
252
+ var badArg = await _catch(function () { return b.db.getTableMetadata({ table: "" }); });
253
+ check("getTableMetadata({ table: '' }) throws db/bad-table-arg",
254
+ badArg && badArg.code === "db/bad-table-arg");
255
+
256
+ var badFmt = await _catch(function () {
257
+ return b.db.getTableMetadata({ table: "orders", format: "yaml" });
258
+ });
259
+ check("getTableMetadata bad format throws db/bad-format",
260
+ badFmt && badFmt.code === "db/bad-format");
261
+
262
+ var js = b.db.getTableMetadata({ table: "orders", format: "json-schema-2020-12" });
263
+ check("json-schema output carries the 2020-12 $schema", /2020-12/.test(js["$schema"]));
264
+ check("json-schema marks NOT NULL column required", js.required.indexOf("total") !== -1);
265
+ check("json-schema marks nullable column as anyOf union",
266
+ Array.isArray(js.properties.note.anyOf));
267
+ check("json-schema annotates sealed column",
268
+ js.properties.note["x-blamejs-sealed"] === true);
269
+ check("json-schema annotates derived-hash column",
270
+ js.properties.totalHash["x-blamejs-derived-from"] === "total");
271
+ } finally {
272
+ await helpers.teardownTestDb(tmpDir);
273
+ }
274
+ }
275
+
276
+ // --- transaction() --------------------------------------------------------
277
+
278
+ async function testTransaction() {
279
+ var tmpDir = _mkTmp("db-cov-txn-");
280
+ try {
281
+ await _plainInit(tmpDir, [{ name: "ledger", columns: { _id: "TEXT PRIMARY KEY", bal: "INTEGER" } }],
282
+ { frameworkTables: false, auditSigning: false });
283
+
284
+ var badFn = await _catch(function () { return b.db.transaction("not-a-fn"); });
285
+ check("transaction(non-fn) throws db/bad-transaction-fn",
286
+ badFn && badFn.code === "db/bad-transaction-fn");
287
+
288
+ var ret = b.db.transaction(function () {
289
+ b.db.from("ledger").insertOne({ _id: "a", bal: 1 });
290
+ return "committed";
291
+ });
292
+ check("transaction returns the fn's value", ret === "committed");
293
+ check("committed row is present", b.db.from("ledger").where({ _id: "a" }).first().bal === 1);
294
+
295
+ // A throw inside the body rolls back and re-propagates.
296
+ var rolled = await _catch(function () {
297
+ return b.db.transaction(function () {
298
+ b.db.from("ledger").insertOne({ _id: "b", bal: 2 });
299
+ throw new Error("boom-in-txn");
300
+ });
301
+ });
302
+ check("transaction re-propagates the body error", rolled && /boom-in-txn/.test(rolled.message));
303
+ check("rolled-back row is absent",
304
+ !b.db.from("ledger").where({ _id: "b" }).first());
305
+ } finally {
306
+ _teardownPlain(tmpDir);
307
+ }
308
+ }
309
+
310
+ // --- exportCsv validation + success ---------------------------------------
311
+
312
+ async function testExportCsv() {
313
+ var tmpDir = _mkTmp("db-cov-csv-");
314
+ try {
315
+ await helpers.setupTestDb(tmpDir, [{
316
+ name: "orders",
317
+ columns: {
318
+ _id: "TEXT PRIMARY KEY", note: "TEXT", total: "INTEGER NOT NULL",
319
+ createdAt: "INTEGER NOT NULL", raw: "BLOB", sealedRaw: "BLOB",
320
+ },
321
+ // `raw` is a plain BLOB (reads back as a Uint8Array); `sealedRaw` is a
322
+ // SEALED BLOB — cryptoField unseals it to a real Node Buffer, so the CSV
323
+ // projector takes the Buffer→base64 arm rather than the String() arm.
324
+ sealedFields: ["note", "sealedRaw"],
325
+ }]);
326
+
327
+ var noOpts = await _catch(function () { return b.db.exportCsv(); });
328
+ check("exportCsv() no opts throws db/bad-export-opts",
329
+ noOpts && noOpts.code === "db/bad-export-opts");
330
+
331
+ var noTable = await _catch(function () { return b.db.exportCsv({}); });
332
+ check("exportCsv missing table throws", noTable !== null);
333
+
334
+ var unknown = await _catch(function () { return b.db.exportCsv({ table: "ghost" }); });
335
+ check("exportCsv unknown table throws db/unknown-table",
336
+ unknown && unknown.code === "db/unknown-table");
337
+
338
+ var badCol = await _catch(function () {
339
+ return b.db.exportCsv({ table: "orders", columns: ["_id", "not_a_col"] });
340
+ });
341
+ check("exportCsv unknown column throws db/bad-export-column",
342
+ badCol && badCol.code === "db/bad-export-column");
343
+
344
+ var badFmt = await _catch(function () {
345
+ return b.db.exportCsv({ table: "orders", format: "tsv" });
346
+ });
347
+ check("exportCsv bad format throws db/bad-export-format",
348
+ badFmt && badFmt.code === "db/bad-export-format");
349
+
350
+ var badSigner = await _catch(function () {
351
+ return b.db.exportCsv({ table: "orders", signWith: { sign: function () {} } });
352
+ });
353
+ check("exportCsv incomplete signer throws db/bad-signer",
354
+ badSigner && badSigner.code === "db/bad-signer");
355
+
356
+ var throwingSigner = await _catch(function () {
357
+ return b.db.exportCsv({
358
+ table: "orders",
359
+ signWith: {
360
+ sign: function () { throw new Error("hsm-down"); },
361
+ getPublicKey: function () { return ""; },
362
+ getAlgorithm: function () { return "x"; },
363
+ getPublicKeyFingerprint: function () { return "y"; },
364
+ },
365
+ });
366
+ });
367
+ check("exportCsv signer that throws surfaces db/sign-failed",
368
+ throwingSigner && throwingSigner.code === "db/sign-failed");
369
+
370
+ // Success path: BOM + ISO timestamp cast + Buffer base64 + null → "".
371
+ b.db.from("orders").insertOne({ _id: "o1", note: "hi", total: 100, createdAt: Date.now(), raw: Buffer.from("AB"), sealedRaw: Buffer.from("AB") });
372
+ b.db.from("orders").insertOne({ _id: "o2", note: null, total: 200, createdAt: Date.now() });
373
+ var out = b.db.exportCsv({
374
+ table: "orders", bom: true, timestampFields: ["createdAt"], signWith: b.auditSign,
375
+ });
376
+ check("exportCsv success reports 2 rows", out.rowCount === 2);
377
+ check("exportCsv emits a SHA3-512 (128 hex chars)", out.sha3_512.length === 128);
378
+ check("exportCsv text carries the UTF-8 BOM", out.csv.charCodeAt(0) === 0xFEFF);
379
+ check("exportCsv attaches a signature block", !!out.signature && typeof out.signature.value === "string");
380
+ // The sealed BLOB's unsealed Buffer takes the Buffer.isBuffer→base64 arm;
381
+ // Buffer.from("AB").toString("base64") === "QUI=". (The plain-BLOB `raw`
382
+ // column reads back as a Uint8Array and stringifies to "65,66" instead.)
383
+ check("exportCsv base64-encodes a sealed BLOB column's Buffer value",
384
+ out.csv.indexOf("QUI=") !== -1);
385
+ } finally {
386
+ await helpers.teardownTestDb(tmpDir);
387
+ }
388
+ }
389
+
390
+ // --- #452 exportCsv parity on a reserved-word table name ------------------
391
+
392
+ async function testExportCsvReservedWordTable() {
393
+ // #452 — a schema-valid table whose name is a SQL keyword (b.db.from()
394
+ // accepts it via allowReserved) must export too; the validate-only guard in
395
+ // exportCsv used to reject it stricter than db.from() (sql/reserved-word).
396
+ var tmpDir = _mkTmp("db-cov-csv-kw-");
397
+ try {
398
+ await helpers.setupTestDb(tmpDir, [{
399
+ name: "select", // SQL keyword table name
400
+ columns: { _id: "TEXT PRIMARY KEY", note: "TEXT" },
401
+ }]);
402
+ var err = await _catch(function () { return b.db.exportCsv({ table: "select" }); });
403
+ check("#452: exportCsv on a keyword-named table is not rejected as reserved-word",
404
+ err === null || err.code !== "sql/reserved-word");
405
+ } finally {
406
+ await helpers.teardownTestDb(tmpDir);
407
+ }
408
+ }
409
+
410
+ // --- stream() error + limit branches --------------------------------------
411
+
412
+ async function testStream() {
413
+ var tmpDir = _mkTmp("db-cov-stream-");
414
+ try {
415
+ await _plainInit(tmpDir, [{
416
+ name: "events", columns: { _id: "TEXT PRIMARY KEY", payload: "TEXT" }, sealedFields: ["payload"],
417
+ }], { frameworkTables: false, auditSigning: false });
418
+ b.db.from("events").insertOne({ _id: "e1", payload: "one" });
419
+ b.db.from("events").insertOne({ _id: "e2", payload: "two" });
420
+ b.db.from("events").insertOne({ _id: "e3", payload: "three" });
421
+
422
+ // prepare() throws on bad SQL → the returned Readable destroys w/ error.
423
+ var badErr = await _drain(b.db.stream("SELECT * FROM missing_table"));
424
+ check("stream over a missing table destroys with an error", badErr.error !== null);
425
+
426
+ // bad per-call streamLimit throws synchronously at the call site.
427
+ var badLimit = await _catch(function () { return b.db.stream("SELECT * FROM events", { streamLimit: 0 }); });
428
+ check("stream bad streamLimit throws db/bad-stream-limit",
429
+ badLimit && badLimit.code === "db/bad-stream-limit");
430
+
431
+ // A limit strictly below the row count exceeds → destroyed with the typed error.
432
+ var over = await _drain(b.db.stream("SELECT * FROM events", { streamLimit: 2 }));
433
+ check("stream past the limit destroys with db/stream-limit-exceeded",
434
+ over.error && over.error.code === "db/stream-limit-exceeded");
435
+
436
+ // Sealed-column auto-unseal via opts.table + a positional param.
437
+ var okRun = await _drain(b.db.stream("SELECT * FROM events WHERE _id != ?", "e_none", { table: "events" }));
438
+ check("stream with opts.table + param yields unsealed rows", okRun.rows.length === 3);
439
+ check("stream auto-unseals the sealed column",
440
+ okRun.rows.every(function (r) { return typeof r.payload === "string" && r.payload.indexOf("vault") === -1; }));
441
+
442
+ // A trailing positional (non-object) param with no opts object takes the
443
+ // params-only branch (last arg is a SQL binding, not an options bag).
444
+ var posOnly = await _drain(b.db.stream("SELECT * FROM events WHERE _id != ?", "e1"));
445
+ check("stream with a positional param and no opts binds it as a parameter",
446
+ posOnly.error === null && posOnly.rows.length === 2);
447
+ } finally {
448
+ _teardownPlain(tmpDir);
449
+ }
450
+ }
451
+
452
+ // Drain a Readable to completion, capturing rows + any error.
453
+ function _drain(readable) {
454
+ return new Promise(function (resolve) {
455
+ var rows = [];
456
+ readable.on("data", function (r) { rows.push(r); });
457
+ readable.on("end", function () { resolve({ rows: rows, error: null }); });
458
+ readable.on("error", function (e) { resolve({ rows: rows, error: e }); });
459
+ });
460
+ }
461
+
462
+ // --- prepare() cache + LRU eviction ---------------------------------------
463
+
464
+ async function testPrepareCache() {
465
+ var tmpDir = _mkTmp("db-cov-prep-");
466
+ try {
467
+ await _plainInit(tmpDir, [], { frameworkTables: false, auditSigning: false });
468
+
469
+ var a = b.db.prepare("SELECT 1 AS one");
470
+ var again = b.db.prepare("SELECT 1 AS one");
471
+ check("prepare() returns the cached Statement for the same SQL", a === again);
472
+
473
+ // Fill past the 256-entry cap so the first distinct SQL is evicted, then
474
+ // re-prepare it — a fresh Statement means the LRU dropped it.
475
+ var first = b.db.prepare("SELECT 0 AS n");
476
+ for (var i = 1; i <= 300; i++) {
477
+ b.db.prepare("SELECT " + i + " AS n");
478
+ }
479
+ var firstAgain = b.db.prepare("SELECT 0 AS n");
480
+ check("prepare() LRU evicts the oldest entry past the cap", first !== firstAgain);
481
+ } finally {
482
+ _teardownPlain(tmpDir);
483
+ }
484
+ }
485
+
486
+ // --- runSql / exec DDL audit branches -------------------------------------
487
+
488
+ async function testRunSql() {
489
+ var tmpDir = _mkTmp("db-cov-runsql-");
490
+ try {
491
+ await _plainInit(tmpDir, [], { frameworkTables: false, auditSigning: false });
492
+
493
+ b.db.runSql("CREATE TABLE scratch (id INTEGER PRIMARY KEY)");
494
+ check("runSql executes a DDL CREATE",
495
+ b.db.prepare("SELECT name FROM sqlite_master WHERE name='scratch'").get().name === "scratch");
496
+
497
+ // exec alias exists and runs DDL too.
498
+ b.db.exec("CREATE TABLE scratch2 (id INTEGER PRIMARY KEY)");
499
+ check("db.exec alias runs DDL",
500
+ b.db.prepare("SELECT name FROM sqlite_master WHERE name='scratch2'").get().name === "scratch2");
501
+
502
+ // A malformed DDL exercises the failure-audit branch and re-throws.
503
+ var ddlErr = await _catch(function () { return b.db.runSql("CREATE TABLE"); });
504
+ check("runSql malformed DDL re-throws", ddlErr !== null);
505
+
506
+ // Non-DDL raw statement runs through the non-audited path.
507
+ b.db.runSql("INSERT INTO scratch (id) VALUES (7)");
508
+ check("runSql non-DDL DML executes",
509
+ b.db.prepare("SELECT id FROM scratch WHERE id=7").get().id === 7);
510
+ } finally {
511
+ _teardownPlain(tmpDir);
512
+ }
513
+ }
514
+
515
+ // --- vacuumAfterErase -----------------------------------------------------
516
+
517
+ async function testVacuum() {
518
+ var tmpDir = _mkTmp("db-cov-vac-");
519
+ try {
520
+ await _plainInit(tmpDir, [], { frameworkTables: false, auditSigning: false });
521
+
522
+ var badMode = await _catch(function () { return b.db.vacuumAfterErase({ mode: "sideways" }); });
523
+ check("vacuumAfterErase bad mode throws db/bad-vacuum-mode",
524
+ badMode && badMode.code === "db/bad-vacuum-mode");
525
+
526
+ var badPages = await _catch(function () { return b.db.vacuumAfterErase({ mode: "incremental", pages: -3 }); });
527
+ check("vacuumAfterErase bad pages throws db/bad-vacuum-pages",
528
+ badPages && badPages.code === "db/bad-vacuum-pages");
529
+
530
+ b.db.vacuumAfterErase({ mode: "incremental", pages: 5 });
531
+ b.db.vacuumAfterErase(); // default incremental / 1000 pages
532
+ b.db.vacuumAfterErase({ mode: "full" });
533
+ check("vacuumAfterErase incremental + full succeed", true);
534
+
535
+ b.db.close();
536
+ var notInit = await _catch(function () { return b.db.vacuumAfterErase({ mode: "full" }); });
537
+ check("vacuumAfterErase after close throws db/not-initialized",
538
+ notInit && notInit.code === "db/not-initialized");
539
+ } finally {
540
+ _teardownPlain(tmpDir);
541
+ }
542
+ }
543
+
544
+ // --- declareWorm ----------------------------------------------------------
545
+
546
+ async function testDeclareWorm() {
547
+ var tmpDir = _mkTmp("db-cov-worm-");
548
+ try {
549
+ await helpers.setupTestDb(tmpDir, [
550
+ { name: "blotter", columns: { _id: "TEXT PRIMARY KEY", sym: "TEXT" } },
551
+ ]);
552
+
553
+ var noTables = await _catch(function () { return b.db.declareWorm({}); });
554
+ check("declareWorm missing tables throws", noTables !== null && noTables.name === "WormViolationError");
555
+
556
+ // Called with the args object omitted entirely — the `args = args || {}`
557
+ // normalization must still land on the tables-required throw (not a
558
+ // TypeError reading .tables off undefined).
559
+ var bareWorm = await _catch(function () { return b.db.declareWorm(); });
560
+ check("declareWorm() with no args at all throws WormViolationError",
561
+ bareWorm && bareWorm.name === "WormViolationError" && bareWorm.code === "BAD_OPT");
562
+
563
+ var empty = await _catch(function () { return b.db.declareWorm({ tables: [] }); });
564
+ check("declareWorm empty tables throws", empty !== null);
565
+
566
+ var badId = await _catch(function () { return b.db.declareWorm({ tables: ["bad name!"] }); });
567
+ check("declareWorm invalid identifier throws", badId !== null);
568
+
569
+ var badPosture = await _catch(function () { return b.db.declareWorm({ tables: ["blotter"], posture: 5 }); });
570
+ check("declareWorm non-string posture throws", badPosture !== null);
571
+
572
+ var reserved = await _catch(function () { return b.db.declareWorm({ tables: ["audit_log"] }); });
573
+ check("declareWorm on framework audit_log throws RESERVED",
574
+ reserved && reserved.code === "RESERVED");
575
+
576
+ var declared = b.db.declareWorm({ tables: ["blotter"], posture: "finra-4511" });
577
+ check("declareWorm returns the declared table list", declared.tables[0] === "blotter");
578
+
579
+ // The WORM trigger now blocks UPDATE + DELETE on the declared table.
580
+ b.db.from("blotter").insertOne({ _id: "t1", sym: "AAPL" });
581
+ var upd = await _catch(function () {
582
+ return b.db.from("blotter").where({ _id: "t1" }).updateOne({ sym: "MSFT" });
583
+ });
584
+ check("WORM trigger blocks UPDATE on the declared table", upd !== null);
585
+ } finally {
586
+ await helpers.teardownTestDb(tmpDir);
587
+ }
588
+ }
589
+
590
+ // --- declareRequireDualControl + _checkDualControlGate --------------------
591
+
592
+ async function testDualControl() {
593
+ var tmpDir = _mkTmp("db-cov-dc-");
594
+ try {
595
+ await helpers.setupTestDb(tmpDir, [
596
+ { name: "charts", columns: { _id: "TEXT PRIMARY KEY", body: "TEXT" } },
597
+ ]);
598
+
599
+ var noTables = await _catch(function () { return b.db.declareRequireDualControl({}); });
600
+ check("declareRequireDualControl no tables throws db/dual-control-bad-tables",
601
+ noTables && noTables.code === "db/dual-control-bad-tables");
602
+
603
+ // Called with the args object omitted entirely — the `args = args || {}`
604
+ // normalization must reach the same bad-tables throw.
605
+ var bareDc = await _catch(function () { return b.db.declareRequireDualControl(); });
606
+ check("declareRequireDualControl() with no args at all throws db/dual-control-bad-tables",
607
+ bareDc && bareDc.code === "db/dual-control-bad-tables");
608
+
609
+ var badId = await _catch(function () { return b.db.declareRequireDualControl({ tables: ["bad;name"] }); });
610
+ check("declareRequireDualControl bad identifier throws", badId !== null);
611
+
612
+ var badQuorum = await _catch(function () { return b.db.declareRequireDualControl({ tables: ["charts"], m: 1 }); });
613
+ check("declareRequireDualControl m<2 throws db/dual-control-bad-quorum",
614
+ badQuorum && badQuorum.code === "db/dual-control-bad-quorum");
615
+
616
+ var badPosture = await _catch(function () {
617
+ return b.db.declareRequireDualControl({ tables: ["charts"], posture: 9 });
618
+ });
619
+ check("declareRequireDualControl non-string posture throws db/dual-control-bad-posture",
620
+ badPosture && badPosture.code === "db/dual-control-bad-posture");
621
+
622
+ check("_checkDualControlGate returns null for an undeclared table",
623
+ b.db._checkDualControlGate("charts") === null);
624
+
625
+ var gate = b.db.declareRequireDualControl({ tables: ["charts"], m: 2, n: 3, posture: "hipaa" });
626
+ check("declareRequireDualControl returns quorum tuple", gate.m === 2 && gate.n === 3);
627
+
628
+ var row = b.db._checkDualControlGate("charts");
629
+ check("_checkDualControlGate returns the registered gate", row && row.m === 2 && row.n === 3);
630
+
631
+ // Declaring a gate WITHOUT a posture drives the `posture || null`
632
+ // fallback on the registry write, the audit metadata, and the return
633
+ // tuple — the omitted posture normalizes to null everywhere.
634
+ var noPosture = b.db.declareRequireDualControl({ tables: ["charts"], m: 2, n: 4 });
635
+ check("declareRequireDualControl without a posture returns posture:null",
636
+ noPosture.posture === null && noPosture.m === 2 && noPosture.n === 4);
637
+ check("_checkDualControlGate reflects the re-declared (null-posture) gate",
638
+ b.db._checkDualControlGate("charts").posture === null);
639
+ } finally {
640
+ await helpers.teardownTestDb(tmpDir);
641
+ }
642
+ }
643
+
644
+ // --- eraseHard ------------------------------------------------------------
645
+
646
+ async function testEraseHard() {
647
+ var tmpDir = _mkTmp("db-cov-erase-");
648
+ try {
649
+ await helpers.setupTestDb(tmpDir, [
650
+ { name: "gated", columns: { _id: "TEXT PRIMARY KEY", ssn: "TEXT" }, sealedFields: ["ssn"] },
651
+ { name: "plainrows", columns: { _id: "TEXT PRIMARY KEY", ssn: "TEXT" }, sealedFields: ["ssn"] },
652
+ ]);
653
+
654
+ var badRow = await _catch(function () { return b.db.eraseHard("gated", "", { reason: "x here now" }); });
655
+ check("eraseHard empty rowId throws db/erase-hard-bad-row-id",
656
+ badRow && badRow.code === "db/erase-hard-bad-row-id");
657
+
658
+ var noReason = await _catch(function () { return b.db.eraseHard("plainrows", "r1", {}); });
659
+ check("eraseHard missing reason throws db/erase-hard-no-reason",
660
+ noReason && noReason.code === "db/erase-hard-no-reason");
661
+
662
+ // Called with the opts argument omitted entirely — the `opts = opts || {}`
663
+ // normalization must reach the missing-reason throw rather than a
664
+ // TypeError reading .reason off undefined.
665
+ var bareErase = await _catch(function () { return b.db.eraseHard("plainrows", "r1"); });
666
+ check("eraseHard(table, rowId) with no opts arg throws db/erase-hard-no-reason",
667
+ bareErase && bareErase.code === "db/erase-hard-no-reason");
668
+
669
+ // Non-gated, non-WORM table: success.
670
+ b.db.from("plainrows").insertOne({ _id: "r1", ssn: "111-11-1111" });
671
+ var ok = b.db.eraseHard("plainrows", "r1", { reason: "gdpr art 17 erasure request" });
672
+ check("eraseHard deletes the row (rowsDeleted === 1)", ok.rowsDeleted === 1);
673
+ check("eraseHard reports a numeric durationMs", typeof ok.durationMs === "number");
674
+ check("eraseHard actually removed the row",
675
+ !b.db.from("plainrows").where({ _id: "r1" }).first());
676
+
677
+ // Erasing a row that isn't present deletes nothing — the `changes || 0`
678
+ // fallback reports zero rather than a falsy changes value.
679
+ var absent = b.db.eraseHard("plainrows", "no-such-row", { reason: "idempotent erasure sweep" });
680
+ check("eraseHard on an absent row reports rowsDeleted === 0", absent.rowsDeleted === 0);
681
+
682
+ // Gated table: refused without a grant.
683
+ b.db.declareRequireDualControl({ tables: ["gated"], m: 2, n: 3, posture: "hipaa" });
684
+ b.db.from("gated").insertOne({ _id: "g1", ssn: "222-22-2222" });
685
+ var denied = await _catch(function () { return b.db.eraseHard("gated", "g1", { reason: "erase please now" }); });
686
+ check("eraseHard on a gated table without a grant is refused",
687
+ denied && denied.code === "db/erase-hard-dual-control-required");
688
+
689
+ var notReady = await _catch(function () {
690
+ return b.db.eraseHard("gated", "g1", { reason: "erase please now", dualControlGrant: { ready: false } });
691
+ });
692
+ check("eraseHard with an unconsumed grant throws db/erase-hard-grant-not-ready",
693
+ notReady && notReady.code === "db/erase-hard-grant-not-ready");
694
+
695
+ var gatedOk = b.db.eraseHard("gated", "g1", { reason: "erase please now", dualControlGrant: { ready: true } });
696
+ check("eraseHard with a ready grant succeeds", gatedOk.rowsDeleted === 1);
697
+ } finally {
698
+ await helpers.teardownTestDb(tmpDir);
699
+ }
700
+ }
701
+
702
+ // --- purgeAuditChain ------------------------------------------------------
703
+
704
+ async function testPurgeAuditChain() {
705
+ var tmpDir = _mkTmp("db-cov-purge-");
706
+ try {
707
+ await helpers.setupTestDb(tmpDir, [{ name: "t", columns: { _id: "TEXT PRIMARY KEY" } }]);
708
+
709
+ var badCounter = await _catch(function () { return b.db.purgeAuditChain({ lastPurgedCounter: -1 }); });
710
+ check("purgeAuditChain negative counter throws db/bad-purge-counter",
711
+ badCounter && badCounter.code === "db/bad-purge-counter");
712
+
713
+ var nanCounter = await _catch(function () { return b.db.purgeAuditChain({ lastPurgedCounter: "abc" }); });
714
+ check("purgeAuditChain non-numeric counter throws db/bad-purge-counter",
715
+ nanCounter && nanCounter.code === "db/bad-purge-counter");
716
+
717
+ var res = await b.db.purgeAuditChain({ lastPurgedCounter: 0 });
718
+ check("purgeAuditChain returns numeric rowsDeleted", typeof res.rowsDeleted === "number");
719
+ check("purgeAuditChain returns numeric checkpointsDeleted", typeof res.checkpointsDeleted === "number");
720
+ } finally {
721
+ await helpers.teardownTestDb(tmpDir);
722
+ }
723
+ }
724
+
725
+ // --- hashFor / hashCandidatesFor ------------------------------------------
726
+
727
+ async function testHashHelpers() {
728
+ var tmpDir = _mkTmp("db-cov-hash-");
729
+ try {
730
+ await helpers.setupTestDb(tmpDir); // default users table w/ email→emailHash
731
+ var h = b.db.hashFor("users", "email", "alice@example.com");
732
+ check("hashFor returns a string digest for a derived field", typeof h === "string" && h.length > 0);
733
+ check("hashFor returns null for a field with no derived hash",
734
+ b.db.hashFor("users", "name", "Alice") === null);
735
+
736
+ var cands = b.db.hashCandidatesFor("users", "email", "alice@example.com");
737
+ check("hashCandidatesFor returns { field, values } for a derived field",
738
+ cands && cands.field === "emailHash" && Array.isArray(cands.values));
739
+ check("hashCandidatesFor returns null for a non-derived field",
740
+ b.db.hashCandidatesFor("users", "name", "Alice") === null);
741
+ } finally {
742
+ await helpers.teardownTestDb(tmpDir);
743
+ }
744
+ }
745
+
746
+ // --- integrityCheck + integrityMonitor ------------------------------------
747
+
748
+ async function testIntegrity() {
749
+ var tmpDir = _mkTmp("db-cov-integ-");
750
+ try {
751
+ await _plainInit(tmpDir, [], { frameworkTables: false, auditSigning: false });
752
+
753
+ check("integrityCheck reports ok on a healthy db", b.db.integrityCheck() === "ok");
754
+
755
+ var badInterval = await _catch(function () { return b.db.integrityMonitor({ intervalMs: -5 }); });
756
+ check("integrityMonitor rejects a non-positive intervalMs", badInterval instanceof TypeError);
757
+
758
+ var mon = b.db.integrityMonitor({ intervalMs: C.TIME.hours(24), audit: false });
759
+ check("integrityMonitor returns a handle with stop()", typeof mon.stop === "function");
760
+ mon.stop();
761
+ mon.stop(); // idempotent second stop
762
+ check("integrityMonitor stop() is idempotent", true);
763
+
764
+ // No-opts call exercises the `opts || {}` + default 24h-interval
765
+ // fallbacks; stop it immediately so the timer never fires.
766
+ var defMon = b.db.integrityMonitor();
767
+ check("integrityMonitor() with no opts returns a handle", typeof defMon.stop === "function");
768
+ defMon.stop();
769
+ } finally {
770
+ _teardownPlain(tmpDir);
771
+ }
772
+ }
773
+
774
+ // --- applyPosture / getActivePosture --------------------------------------
775
+
776
+ async function testApplyPosture() {
777
+ b.db._resetForTest();
778
+ check("applyPosture('') returns null", b.db.applyPosture("") === null);
779
+ check("applyPosture(non-string) returns null", b.db.applyPosture(123) === null);
780
+ var res = b.db.applyPosture("pci-dss");
781
+ check("applyPosture records posture + dbInitialized flag",
782
+ res.posture === "pci-dss" && res.dbInitialized === false);
783
+ check("getActivePosture reflects the last applied posture",
784
+ b.db.getActivePosture() === "pci-dss");
785
+ }
786
+
787
+ // --- close idempotency + generation counter -------------------------------
788
+
789
+ async function testCloseAndGeneration() {
790
+ var tmpDir = _mkTmp("db-cov-close-");
791
+ try {
792
+ await _plainInit(tmpDir, [{ name: "t", columns: { _id: "TEXT PRIMARY KEY" } }],
793
+ { frameworkTables: false, auditSigning: false });
794
+
795
+ var genBefore = b.db._dbGeneration();
796
+ check("_dbGeneration is a number after init", typeof genBefore === "number");
797
+
798
+ b.db.close();
799
+ var genAfter = b.db._dbGeneration();
800
+ check("_dbGeneration bumps on close", genAfter > genBefore);
801
+
802
+ b.db.close(); // idempotent no-op after the first close
803
+ check("close() after close is a no-op (generation unchanged)",
804
+ b.db._dbGeneration() === genAfter);
805
+
806
+ var guarded = await _catch(function () { return b.db.from("t"); });
807
+ check("from() after close reports not-initialized", guarded && guarded.code === "db/not-initialized");
808
+ } finally {
809
+ _teardownPlain(tmpDir);
810
+ }
811
+ }
812
+
813
+ // --- tmpfs storage-headroom write gate (fault-injected statfs) -------------
814
+
815
+ async function testStorageGuard() {
816
+ var tmpDir = _mkTmp("db-cov-storage-");
817
+ try {
818
+ // One vault for the whole test — a second vault.init would rotate the
819
+ // keypair and fail to unseal the db.key.enc written on the first attempt.
820
+ await _freshVault(tmpDir);
821
+
822
+ // Bad minFreeBytes surfaces at config time (encrypted branch, after the
823
+ // key file is materialized — hence vault must be up first).
824
+ var badMin = await _catch(function () {
825
+ return b.db.init({
826
+ dataDir: tmpDir, tmpDir: path.join(tmpDir, "tmpfs"), allowNonTmpfsTmpDir: true,
827
+ frameworkTables: false, auditSigning: false, minFreeBytes: -5,
828
+ schema: [{ name: "t", columns: { _id: "TEXT PRIMARY KEY" } }],
829
+ });
830
+ });
831
+ check("init negative minFreeBytes throws db/bad-min-free-bytes",
832
+ badMin && badMin.code === "db/bad-min-free-bytes");
833
+ b.db._resetForTest();
834
+
835
+ // Encrypted mode with an injectable free-space reader (reuses the vault
836
+ // + key file from above).
837
+ var freeBytes = C.BYTES.mib(100);
838
+ await b.db.init({
839
+ dataDir: tmpDir, tmpDir: path.join(tmpDir, "tmpfs"), allowNonTmpfsTmpDir: true,
840
+ frameworkTables: false, auditSigning: false,
841
+ minFreeBytes: C.BYTES.mib(16),
842
+ _statfsForTest: function () { return { bavail: freeBytes, bsize: 1 }; },
843
+ schema: [{ name: "t", columns: { _id: "TEXT PRIMARY KEY", v: "TEXT" } }],
844
+ });
845
+
846
+ var healthy = b.db._probeStorageForTest();
847
+ check("storage probe: writes allowed when headroom is healthy", healthy.writesRefused === false);
848
+
849
+ // Drop below the floor → growth writes refused.
850
+ freeBytes = C.BYTES.kib(1);
851
+ var low = b.db._probeStorageForTest();
852
+ check("storage probe flips writesRefused when free space is low", low.writesRefused === true);
853
+
854
+ var refused = await _catch(function () { return b.db.from("t").insertOne({ _id: "x", v: "1" }); });
855
+ check("growth write is refused with db/storage-low under low headroom",
856
+ refused && refused.code === "db/storage-low");
857
+
858
+ // A writable-CTE (WITH ... INSERT) is also a growth write — the gate
859
+ // classifies it by effective write syntax, not just the leading keyword.
860
+ var refusedCte = await _catch(function () {
861
+ var st = b.db.prepare("WITH c AS (SELECT 1) INSERT INTO t (_id, v) SELECT 'z', '9'");
862
+ return st.run();
863
+ });
864
+ check("a WITH-prefixed writable-CTE growth write is refused under low headroom",
865
+ refusedCte && refusedCte.code === "db/storage-low");
866
+
867
+ // Reads keep serving even while writes are refused.
868
+ var readOk = await _catch(function () { return b.db.from("t").all(); });
869
+ check("reads still serve while writes are refused", readOk === null);
870
+
871
+ // Recover headroom → writes re-enabled.
872
+ freeBytes = C.BYTES.mib(100);
873
+ var recovered = b.db._probeStorageForTest();
874
+ check("storage probe clears writesRefused after recovery", recovered.writesRefused === false);
875
+
876
+ b.db.from("t").insertOne({ _id: "y", v: "2" });
877
+ check("growth write succeeds after headroom recovers",
878
+ b.db.from("t").where({ _id: "y" }).first().v === "2");
879
+ } finally {
880
+ _teardownPlain(tmpDir);
881
+ }
882
+ }
883
+
884
+ // --- tmpfs resolution: BLAMEJS_TMPDIR + fail-closed no-tmpfs -----------------
885
+
886
+ async function testTmpfsResolution() {
887
+ var savedTmpEnv = process.env.BLAMEJS_TMPDIR;
888
+ var tmpDir = _mkTmp("db-cov-tmpfs-");
889
+ try {
890
+ // No opts.tmpDir and no BLAMEJS_TMPDIR: encrypted mode (the default) must
891
+ // resolve a tmpfs for the decrypted working copy. On a host without
892
+ // /dev/shm the resolver returns null and boot fail-closes with
893
+ // db/no-tmpfs; on a host WITH /dev/shm it resolves that mount and boots.
894
+ delete process.env.BLAMEJS_TMPDIR;
895
+ await _freshVault(tmpDir);
896
+ var noTmp = await _catch(function () {
897
+ return b.db.init({ dataDir: tmpDir, atRest: "encrypted", schema: [],
898
+ frameworkTables: false, auditSigning: false, minFreeBytes: 0 });
899
+ });
900
+ if (noTmp) {
901
+ check("encrypted init with no resolvable tmpfs fail-closes db/no-tmpfs",
902
+ noTmp.code === "db/no-tmpfs");
903
+ } else {
904
+ check("encrypted init resolved a host tmpfs and booted",
905
+ b.db.getMode() === "encrypted");
906
+ }
907
+ b.db._resetForTest();
908
+
909
+ // BLAMEJS_TMPDIR supplies the working-copy mount when opts.tmpDir is
910
+ // omitted. (The Linux-only tmpfs heuristic is skipped on non-Linux;
911
+ // allowNonTmpfsTmpDir downgrades it to a warning where it does run.)
912
+ var envTmpfs = path.join(tmpDir, "envtmpfs");
913
+ fs.mkdirSync(envTmpfs, { recursive: true });
914
+ process.env.BLAMEJS_TMPDIR = envTmpfs;
915
+ await _freshVault(tmpDir);
916
+ await b.db.init({ dataDir: tmpDir, atRest: "encrypted", schema: [],
917
+ allowNonTmpfsTmpDir: true, frameworkTables: false, auditSigning: false, minFreeBytes: 0 });
918
+ check("BLAMEJS_TMPDIR is honored as the encrypted-mode tmpfs mount",
919
+ b.db.getMode() === "encrypted");
920
+ } finally {
921
+ if (savedTmpEnv === undefined) delete process.env.BLAMEJS_TMPDIR;
922
+ else process.env.BLAMEJS_TMPDIR = savedTmpEnv;
923
+ _teardownPlain(tmpDir);
924
+ }
925
+ }
926
+
927
+ // --- tablePrefix passthrough + dataResidency accessor ----------------------
928
+
929
+ async function testTablePrefixAndResidency() {
930
+ var tmpDir = _mkTmp("db-cov-prefix-");
931
+ try {
932
+ await _freshVault(tmpDir);
933
+ // dataDir points at a not-yet-existent nested path so init creates it;
934
+ // the explicit default tablePrefix drives the setTablePrefix passthrough;
935
+ // dataResidency flows to the accessor; a string-form primaryKey exercises
936
+ // the non-array normalize branch.
937
+ var nestedDir = path.join(tmpDir, "nested", "data");
938
+ check("nested dataDir does not exist before init", !fs.existsSync(nestedDir));
939
+ await b.db.init({
940
+ dataDir: nestedDir, atRest: "plain",
941
+ schema: [{ name: "widgets", columns: { code: "TEXT NOT NULL", label: "TEXT" }, primaryKey: "code" }],
942
+ frameworkTables: false, auditSigning: false,
943
+ tablePrefix: "_blamejs_",
944
+ dataResidency: { region: "eu-west-1", strict: true },
945
+ });
946
+ check("init creates a missing nested dataDir", fs.existsSync(nestedDir));
947
+ check("init with an explicit tablePrefix boots normally",
948
+ typeof b.db.from("widgets").all === "function");
949
+ check("getDataResidency returns the declared region",
950
+ b.db.getDataResidency().region === "eu-west-1");
951
+ check("string-form primaryKey normalizes to a single-column array",
952
+ JSON.stringify(b.db.getTableMetadata("widgets").primaryKey) === '["code"]');
953
+ } finally {
954
+ _teardownPlain(tmpDir);
955
+ }
956
+ }
957
+
958
+ // --- encrypted round-trip: stale-tmpdb sweep, snapshot, decryptToTmp -------
959
+
960
+ async function testEncryptedRoundTrip() {
961
+ var tmpDir = _mkTmp("db-cov-enc-");
962
+ var tmpfs = path.join(tmpDir, "tmpfs");
963
+ fs.mkdirSync(tmpfs, { recursive: true });
964
+ // Seed a stale plaintext working copy from a "previous crashed process" so
965
+ // init's cleanStaleTmpDbs sweep has an orphan to reclaim.
966
+ fs.writeFileSync(path.join(tmpfs, "blamejs-staleorphan.db"), "orphan");
967
+ var encOpts = {
968
+ dataDir: tmpDir, tmpDir: tmpfs, allowNonTmpfsTmpDir: true, atRest: "encrypted",
969
+ frameworkTables: false, auditSigning: false, minFreeBytes: 0,
970
+ schema: [{ name: "vaultrows", columns: { _id: "TEXT PRIMARY KEY", v: "TEXT" } }],
971
+ };
972
+ try {
973
+ await _freshVault(tmpDir);
974
+ await b.db.init(encOpts);
975
+ check("stale tmpfs working copy is swept at encrypted boot",
976
+ !fs.existsSync(path.join(tmpfs, "blamejs-staleorphan.db")));
977
+
978
+ b.db.from("vaultrows").insertOne({ _id: "a", v: "persisted" });
979
+
980
+ // snapshot() in encrypted mode returns the sealed envelope Buffer.
981
+ var snap = b.db.snapshot();
982
+ check("encrypted snapshot returns a sealed envelope Buffer",
983
+ Buffer.isBuffer(snap) && snap.length > 26);
984
+
985
+ // flushToDisk re-encrypts the live tmpfs copy to db.enc.
986
+ b.db.flushToDisk();
987
+ b.db.close();
988
+ check("close writes the encrypted-at-rest db.enc", fs.existsSync(path.join(tmpDir, "db.enc")));
989
+
990
+ // Re-init against the SAME vault + dataDir decrypts db.enc back into a
991
+ // fresh tmpfs working copy (decryptToTmp read + AEAD-verified decrypt).
992
+ await b.db.init(encOpts);
993
+ var row = b.db.from("vaultrows").where({ _id: "a" }).first();
994
+ check("encrypted round-trip recovers the row through decryptToTmp",
995
+ row && row.v === "persisted");
996
+ } finally {
997
+ _teardownPlain(tmpDir);
998
+ }
999
+ }
1000
+
1001
+ // --- snapshot() in plain mode (raw bytes, no envelope) ---------------------
1002
+
1003
+ async function testSnapshotPlain() {
1004
+ var tmpDir = _mkTmp("db-cov-snap-");
1005
+ try {
1006
+ await _plainInit(tmpDir, [{ name: "t", columns: { _id: "TEXT PRIMARY KEY" } }],
1007
+ { frameworkTables: false, auditSigning: false });
1008
+ b.db.from("t").insertOne({ _id: "s1" });
1009
+ var snap = b.db.snapshot();
1010
+ check("plain-mode snapshot returns the raw SQLite bytes as a Buffer",
1011
+ Buffer.isBuffer(snap) && snap.length > 0);
1012
+ // A plain snapshot is an unencrypted SQLite file — the magic header is
1013
+ // the ASCII "SQLite format 3\0" string.
1014
+ check("plain snapshot carries the SQLite file header",
1015
+ snap.slice(0, 16).toString("latin1").indexOf("SQLite format 3") === 0);
1016
+ } finally {
1017
+ _teardownPlain(tmpDir);
1018
+ }
1019
+ }
1020
+
1021
+ // --- file-based migrations (run-once) --------------------------------------
1022
+
1023
+ async function testMigrations() {
1024
+ var tmpDir = _mkTmp("db-cov-mig-");
1025
+ var migDir = path.join(tmpDir, "migrations");
1026
+ fs.mkdirSync(migDir, { recursive: true });
1027
+ fs.writeFileSync(path.join(migDir, "001-scratch.js"),
1028
+ "module.exports = { description: 'create mig_scratch', " +
1029
+ "up: function (db) { db.exec('CREATE TABLE mig_scratch (id INTEGER PRIMARY KEY)'); } };");
1030
+ try {
1031
+ await _plainInit(tmpDir, [], { frameworkTables: false, auditSigning: false, migrationDir: migDir });
1032
+ check("migrationDir applies the pending migration",
1033
+ b.db.prepare("SELECT name FROM sqlite_master WHERE name='mig_scratch'").get().name === "mig_scratch");
1034
+
1035
+ // Re-running init against the same dataDir skips the already-applied
1036
+ // migration (run-once ledger).
1037
+ b.db.close();
1038
+ b.db._resetForTest();
1039
+ await b.db.init({ dataDir: tmpDir, atRest: "plain", schema: [],
1040
+ frameworkTables: false, auditSigning: false, migrationDir: migDir });
1041
+ check("a re-run leaves the already-applied migration in place",
1042
+ b.db.prepare("SELECT name FROM sqlite_master WHERE name='mig_scratch'").get().name === "mig_scratch");
1043
+ } finally {
1044
+ _teardownPlain(tmpDir);
1045
+ }
1046
+ }
1047
+
1048
+ // --- WORM posture boot assertion -------------------------------------------
1049
+
1050
+ async function testWormPostureAssertion() {
1051
+ var tmpDir = _mkTmp("db-cov-wormposture-");
1052
+ try {
1053
+ await _freshVault(tmpDir);
1054
+ // Under a record-preservation posture (21 CFR Part 11) with framework
1055
+ // tables enabled, boot refuses unless at least one operator table has a
1056
+ // row-level WORM declaration.
1057
+ b.compliance.set("fda-21cfr11");
1058
+ var refused = await _catch(function () {
1059
+ return b.db.init({ dataDir: tmpDir, atRest: "plain",
1060
+ schema: [{ name: "records", columns: { _id: "TEXT PRIMARY KEY" } }] });
1061
+ });
1062
+ check("boot under a WORM posture with no declared table throws POSTURE_VIOLATION",
1063
+ refused && refused.code === "POSTURE_VIOLATION");
1064
+ } finally {
1065
+ b.compliance.clear();
1066
+ _teardownPlain(tmpDir);
1067
+ }
1068
+ }
1069
+
1070
+ // --- eraseHard legal-hold consult ------------------------------------------
1071
+
1072
+ async function testEraseHardLegalHold() {
1073
+ var tmpDir = _mkTmp("db-cov-lh-");
1074
+ try {
1075
+ await helpers.setupTestDb(tmpDir, [
1076
+ { name: "held", columns: { _id: "TEXT PRIMARY KEY", ssn: "TEXT" }, sealedFields: ["ssn"] },
1077
+ ]);
1078
+ // Registering a legal-hold instance installs the framework singleton
1079
+ // eraseHard consults via _getSingleton().isHeld(subjectId).
1080
+ var holds = b.legalHold.create({ db: b.db, audit: b.audit });
1081
+ holds.place("subject-held", { reason: "litigation hold — matter 42" });
1082
+
1083
+ b.db.from("held").insertOne({ _id: "r1", ssn: "111-11-1111" });
1084
+ var denied = await _catch(function () {
1085
+ return b.db.eraseHard("held", "r1", { reason: "erasure request now", subjectId: "subject-held" });
1086
+ });
1087
+ check("eraseHard refuses a row whose subject is on legal hold",
1088
+ denied && denied.code === "db/erase-hard-legal-hold");
1089
+ check("legally-held row is still present after the refusal",
1090
+ !!b.db.from("held").where({ _id: "r1" }).first());
1091
+
1092
+ // A subject NOT on hold takes the pass-through branch and erases.
1093
+ b.db.from("held").insertOne({ _id: "r2", ssn: "222-22-2222" });
1094
+ var ok = b.db.eraseHard("held", "r2", { reason: "erasure request now", subjectId: "subject-free" });
1095
+ check("eraseHard proceeds when the subject is not on legal hold", ok.rowsDeleted === 1);
1096
+ } finally {
1097
+ b.legalHold._resetForTest();
1098
+ await helpers.teardownTestDb(tmpDir);
1099
+ }
1100
+ }
1101
+
1102
+ // --- integrityMonitor periodic tick (OK path) ------------------------------
1103
+
1104
+ async function testIntegrityMonitorTick() {
1105
+ var tmpDir = _mkTmp("db-cov-montick-");
1106
+ var mon = null;
1107
+ var tapInstalled = false;
1108
+ try {
1109
+ await _plainInit(tmpDir, [], { frameworkTables: false, auditSigning: false });
1110
+ var seen = [];
1111
+ b.observability.setTap(function (name) {
1112
+ if (typeof name === "string" && name.indexOf("db.integrity_check") !== -1) seen.push(name);
1113
+ });
1114
+ tapInstalled = true;
1115
+ // Short interval so the periodic PRAGMA integrity_check tick actually
1116
+ // fires within the test; default audit:true drives the audit-emit branch.
1117
+ mon = b.db.integrityMonitor({ intervalMs: 40 });
1118
+ await helpers.waitUntil(function () { return seen.length >= 1; }, {
1119
+ timeoutMs: 5000, label: "integrityMonitor: first clean tick",
1120
+ });
1121
+ check("integrityMonitor tick emits the db.integrity_check_ok counter",
1122
+ seen.indexOf("db.integrity_check_ok") !== -1);
1123
+ } finally {
1124
+ if (mon) mon.stop();
1125
+ if (tapInstalled) b.observability.setTap(null);
1126
+ _teardownPlain(tmpDir);
1127
+ }
1128
+ }
1129
+
1130
+ // --- getTableMetadata json-schema type mapping across DDL types ------------
1131
+
1132
+ async function testJsonSchemaTypeMapping() {
1133
+ var tmpDir = _mkTmp("db-cov-jsontypes-");
1134
+ try {
1135
+ await _plainInit(tmpDir, [{
1136
+ name: "typed",
1137
+ columns: {
1138
+ _id: "TEXT PRIMARY KEY",
1139
+ n: "INTEGER NOT NULL",
1140
+ amount: "REAL",
1141
+ active: "BOOLEAN",
1142
+ blobby: "BLOB",
1143
+ weird: "GEOMETRY",
1144
+ },
1145
+ }], { frameworkTables: false, auditSigning: false });
1146
+
1147
+ var js = b.db.getTableMetadata({ table: "typed", format: "json-schema-2020-12" });
1148
+ check("json-schema maps INTEGER → integer", js.properties.n.type === "integer");
1149
+ check("json-schema maps REAL → number (nullable union)",
1150
+ js.properties.amount.anyOf[0].type === "number");
1151
+ check("json-schema maps BOOLEAN → boolean",
1152
+ js.properties.active.anyOf[0].type === "boolean");
1153
+ check("json-schema maps BLOB → base64-encoded string",
1154
+ js.properties.blobby.anyOf[0].contentEncoding === "base64");
1155
+ check("json-schema falls back to string for an unrecognized type",
1156
+ js.properties.weird.anyOf[0].type === "string");
1157
+ } finally {
1158
+ _teardownPlain(tmpDir);
1159
+ }
1160
+ }
1161
+
1162
+ // --- exportCsv WHERE filter + explicit column projection -------------------
1163
+
1164
+ async function testExportCsvWhereProjection() {
1165
+ var tmpDir = _mkTmp("db-cov-csv2-");
1166
+ try {
1167
+ await _plainInit(tmpDir, [{
1168
+ name: "sales",
1169
+ columns: { _id: "TEXT PRIMARY KEY", region: "TEXT", cents: "INTEGER NOT NULL" },
1170
+ }], { frameworkTables: false, auditSigning: false });
1171
+ b.db.from("sales").insertOne({ _id: "s1", region: "eu", cents: 100 });
1172
+ b.db.from("sales").insertOne({ _id: "s2", region: "us", cents: 200 });
1173
+ b.db.from("sales").insertOne({ _id: "s3", region: "eu", cents: 300 });
1174
+
1175
+ var out = b.db.exportCsv({
1176
+ table: "sales", columns: ["_id", "cents"], where: { region: "eu" },
1177
+ });
1178
+ check("exportCsv WHERE filter narrows the row set", out.rowCount === 2);
1179
+ check("exportCsv column projection drops unlisted columns",
1180
+ out.csv.indexOf("region") === -1 && out.csv.indexOf("cents") !== -1);
1181
+ } finally {
1182
+ _teardownPlain(tmpDir);
1183
+ }
1184
+ }
1185
+
1186
+ // --- legacy plain-sealed DB key → re-seal with deployment-path AAD ---------
1187
+
1188
+ async function testLegacyKeyReseal() {
1189
+ var tmpDir = _mkTmp("db-cov-legacykey-");
1190
+ var tmpfs = path.join(tmpDir, "tmpfs");
1191
+ fs.mkdirSync(tmpfs, { recursive: true });
1192
+ try {
1193
+ await _freshVault(tmpDir);
1194
+ // Pre-write a pre-AAD key file the way an older release sealed it —
1195
+ // classic vault.seal, no deployment-path binding. Boot must unseal it via
1196
+ // the legacy path and re-seal it in place with the AAD binding.
1197
+ var rawKeyB64 = Buffer.alloc(32, 7).toString("base64");
1198
+ var keyPath = path.join(tmpDir, "db.key.enc");
1199
+ fs.writeFileSync(keyPath, b.vault.seal(rawKeyB64));
1200
+ check("seeded key file is plain vault-sealed (pre-AAD)",
1201
+ fs.readFileSync(keyPath, "utf8").indexOf("vault:") === 0);
1202
+
1203
+ await b.db.init({ dataDir: tmpDir, tmpDir: tmpfs, allowNonTmpfsTmpDir: true,
1204
+ atRest: "encrypted", frameworkTables: false, auditSigning: false, minFreeBytes: 0, schema: [] });
1205
+ check("encrypted boot accepts the legacy plain-sealed DB key",
1206
+ b.db.getMode() === "encrypted");
1207
+ check("boot re-seals the DB key in place with the deployment-path AAD",
1208
+ fs.readFileSync(keyPath, "utf8").indexOf("vault.aad:") === 0);
1209
+ } finally {
1210
+ _teardownPlain(tmpDir);
1211
+ }
1212
+ }
1213
+
1214
+ // --- refuse-to-boot on audit / consent chain break -------------------------
1215
+
1216
+ async function testChainBreakDetection() {
1217
+ // A tampered audit_log row (its rowHash doesn't chain from the prior row)
1218
+ // must halt boot — tamper-evidence compromised is a hard fail-closed.
1219
+ var d1 = _mkTmp("db-cov-chain-a-");
1220
+ var opts1 = { dataDir: d1, atRest: "plain", schema: [], auditSigning: false };
1221
+ try {
1222
+ await _freshVault(d1);
1223
+ await b.db.init(opts1);
1224
+ // Append-only triggers permit INSERT (that's what audit.record does); a
1225
+ // raw insert with a non-chaining rowHash simulates row-level tampering.
1226
+ b.db.prepare("INSERT INTO audit_log (_id, recordedAt, monotonicCounter, action, " +
1227
+ "outcome, prevHash, rowHash, nonce) VALUES (?,?,?,?,?,?,?,?)")
1228
+ .run("tamper-a1", Date.now(), 999000, "tamper.injected", "success",
1229
+ "deadbeef", "not-a-valid-chain-hash", Buffer.from("nonce-bytes-16xx"));
1230
+ b.db.close();
1231
+ b.db._resetForTest();
1232
+ var auditBreak = await _catch(function () { return b.db.init(opts1); });
1233
+ check("boot refuses on a broken audit_log chain (db/audit-chain-break)",
1234
+ auditBreak && auditBreak.code === "db/audit-chain-break");
1235
+ try { b.db.close(); } catch (_e) { /* partially-initialized */ }
1236
+ } finally {
1237
+ _teardownPlain(d1);
1238
+ }
1239
+
1240
+ // With the audit chain intact but the consent_log chain tampered, boot must
1241
+ // still refuse — the consent chain is verified independently.
1242
+ var d2 = _mkTmp("db-cov-chain-c-");
1243
+ var opts2 = { dataDir: d2, atRest: "plain", schema: [], auditSigning: false };
1244
+ try {
1245
+ await _freshVault(d2);
1246
+ await b.db.init(opts2);
1247
+ b.db.prepare("INSERT INTO consent_log (_id, recordedAt, monotonicCounter, subjectId, " +
1248
+ "subjectIdHash, purpose, lawfulBasis, action, channel, prevHash, rowHash, nonce) " +
1249
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)")
1250
+ .run("tamper-c1", Date.now(), 999000, "subj", "subjhash", "marketing", "consent",
1251
+ "grant", "web", "deadbeef", "bad-chain-hash", Buffer.from("nonce-bytes-16xx"));
1252
+ b.db.close();
1253
+ b.db._resetForTest();
1254
+ var consentBreak = await _catch(function () { return b.db.init(opts2); });
1255
+ check("boot refuses on a broken consent_log chain (db/consent-chain-break)",
1256
+ consentBreak && consentBreak.code === "db/consent-chain-break");
1257
+ try { b.db.close(); } catch (_e) { /* partially-initialized */ }
1258
+ } finally {
1259
+ _teardownPlain(d2);
1260
+ }
1261
+ }
1262
+
1263
+ // --- audit.tip rollback detection (OK / rollback / unreadable) --------------
1264
+
1265
+ async function testRollbackDetection() {
1266
+ var tmpDir = _mkTmp("db-cov-rollback-");
1267
+ var opts = { dataDir: tmpDir, atRest: "plain", schema: [], auditSigning: false };
1268
+ var tipPath = path.join(tmpDir, "audit.tip");
1269
+ try {
1270
+ await _freshVault(tmpDir);
1271
+ await b.db.init(opts);
1272
+ // A tip at or below the live MAX(monotonicCounter) is not a rollback.
1273
+ b.db._writeAuditTip({ atMonotonicCounter: 0, rowHash: "seed", signedAt: new Date().toISOString() });
1274
+ b.db.close();
1275
+ b.db._resetForTest();
1276
+ await b.db.init(opts);
1277
+ check("boot with an in-range audit.tip passes the rollback check",
1278
+ b.db.getMode() === "plain");
1279
+
1280
+ // A tip recording a HIGHER counter than the live DB means the DB was
1281
+ // restored from an older snapshot (or rows were deleted) — refuse boot.
1282
+ b.db._writeAuditTip({ atMonotonicCounter: 999999, rowHash: "seed", signedAt: new Date().toISOString() });
1283
+ b.db.close();
1284
+ b.db._resetForTest();
1285
+ var rolled = await _catch(function () { return b.db.init(opts); });
1286
+ check("boot with a rollback-shaped audit.tip throws db/audit-rollback-detected",
1287
+ rolled && rolled.code === "db/audit-rollback-detected");
1288
+ try { b.db.close(); } catch (_e) { /* partially-initialized */ }
1289
+ b.db._resetForTest();
1290
+
1291
+ // A corrupt / schema-invalid audit.tip fail-closes rather than silently
1292
+ // forfeiting rollback protection.
1293
+ fs.writeFileSync(tipPath, "{ not valid json at all ");
1294
+ var unreadable = await _catch(function () { return b.db.init(opts); });
1295
+ check("boot with an unreadable audit.tip throws db/audit-tip-unreadable",
1296
+ unreadable && unreadable.code === "db/audit-tip-unreadable");
1297
+ } finally {
1298
+ _teardownPlain(tmpDir);
1299
+ }
1300
+ }
1301
+
1302
+ // --- _writeAuditTip is a no-op before init (dataDir guard) -----------------
1303
+ async function testWriteAuditTipGuard() {
1304
+ // Fully reset so module-level dataDir is null, then the rollback-sidecar
1305
+ // writer must early-return rather than throw or attempt a write against a
1306
+ // null path — the audit.checkpoint caller relies on this being safe when
1307
+ // no db is open.
1308
+ b.db._resetForTest();
1309
+ var threw = null, ret;
1310
+ try {
1311
+ ret = b.db._writeAuditTip({
1312
+ atMonotonicCounter: 1, rowHash: "x", signedAt: new Date().toISOString(),
1313
+ });
1314
+ } catch (e) { threw = e; }
1315
+ check("_writeAuditTip before init is a silent no-op (dataDir guard)",
1316
+ threw === null && ret === undefined);
1317
+ }
1318
+
1319
+ // --- json-schema type mapping across the remaining DDL heads ---------------
1320
+ async function testJsonSchemaTypeAliases() {
1321
+ var tmpDir = _mkTmp("db-cov-jsontypes2-");
1322
+ try {
1323
+ await _plainInit(tmpDir, [{
1324
+ name: "aliased",
1325
+ columns: {
1326
+ _id: "TEXT PRIMARY KEY",
1327
+ i1: "INT",
1328
+ i2: "BIGINT",
1329
+ f1: "FLOAT",
1330
+ f2: "DOUBLE",
1331
+ f3: "NUMERIC",
1332
+ b1: "BOOL",
1333
+ s1: "VARCHAR",
1334
+ s2: "CHAR",
1335
+ reqInt: "INT NOT NULL",
1336
+ },
1337
+ }], { frameworkTables: false, auditSigning: false });
1338
+
1339
+ var js = b.db.getTableMetadata({ table: "aliased", format: "json-schema-2020-12" });
1340
+ check("json-schema maps INT → integer", js.properties.i1.anyOf[0].type === "integer");
1341
+ check("json-schema maps BIGINT → integer", js.properties.i2.anyOf[0].type === "integer");
1342
+ check("json-schema maps FLOAT → number", js.properties.f1.anyOf[0].type === "number");
1343
+ check("json-schema maps DOUBLE → number", js.properties.f2.anyOf[0].type === "number");
1344
+ check("json-schema maps NUMERIC → number", js.properties.f3.anyOf[0].type === "number");
1345
+ check("json-schema maps BOOL → boolean", js.properties.b1.anyOf[0].type === "boolean");
1346
+ check("json-schema maps VARCHAR → string", js.properties.s1.anyOf[0].type === "string");
1347
+ check("json-schema maps CHAR → string", js.properties.s2.anyOf[0].type === "string");
1348
+ // A NOT NULL integer-alias column keeps the bare type (no null union) and
1349
+ // lands in `required`.
1350
+ check("json-schema NOT NULL INT is a bare integer", js.properties.reqInt.type === "integer");
1351
+ check("json-schema NOT NULL column is required", js.required.indexOf("reqInt") !== -1);
1352
+ } finally {
1353
+ _teardownPlain(tmpDir);
1354
+ }
1355
+ }
1356
+
1357
+ // --- getTableMetadata explicit blamejs format + posture-after-init ----------
1358
+ async function testMetadataBlamejsFormatAndPosture() {
1359
+ var tmpDir = _mkTmp("db-cov-blamejsfmt-");
1360
+ try {
1361
+ await _plainInit(tmpDir, [{
1362
+ name: "acct", columns: { _id: "TEXT PRIMARY KEY", note: "TEXT" }, sealedFields: ["note"],
1363
+ }], { frameworkTables: false, auditSigning: false });
1364
+
1365
+ // Explicit format: "blamejs" takes the structuredClone snapshot branch
1366
+ // (distinct from the string-arg and json-schema branches).
1367
+ var meta = b.db.getTableMetadata({ table: "acct", format: "blamejs" });
1368
+ check("getTableMetadata({format:'blamejs'}) returns the native snapshot",
1369
+ meta && meta.sealedFields.indexOf("note") !== -1);
1370
+
1371
+ // applyPosture WHILE the db is open reports dbInitialized:true (the other
1372
+ // suite exercises the pre-init false branch).
1373
+ var res = b.db.applyPosture("gdpr");
1374
+ check("applyPosture after init reports dbInitialized:true",
1375
+ res.posture === "gdpr" && res.dbInitialized === true);
1376
+ check("getActivePosture reflects the posture set after init",
1377
+ b.db.getActivePosture() === "gdpr");
1378
+ } finally {
1379
+ _teardownPlain(tmpDir);
1380
+ }
1381
+ }
1382
+
1383
+ // --- exportCsv: qualified/quoted table + empty projection + out-of-range ts --
1384
+ async function testExportCsvAdversarialInput() {
1385
+ var tmpDir = _mkTmp("db-cov-csvadv-");
1386
+ try {
1387
+ await _plainInit(tmpDir, [{
1388
+ name: "evts",
1389
+ columns: { _id: "TEXT PRIMARY KEY", region: "TEXT", when: "INTEGER" },
1390
+ }], { frameworkTables: false, auditSigning: false });
1391
+
1392
+ // A schema-qualified / quote-bearing table name is rejected by the
1393
+ // identifier quoter BEFORE the registered-table lookup — refuses the
1394
+ // injection surface rather than passing it into SQL.
1395
+ var qualified = await _catch(function () { return b.db.exportCsv({ table: "main.evts" }); });
1396
+ check("exportCsv on a schema-qualified table name is refused",
1397
+ qualified && qualified.code === "sql/bad-shape");
1398
+ var quoted = await _catch(function () { return b.db.exportCsv({ table: 'ev"ts' }); });
1399
+ check("exportCsv on a quote-bearing table name is refused",
1400
+ quoted && quoted.code === "sql/bad-shape");
1401
+
1402
+ b.db.from("evts").insertOne({ _id: "e1", region: "eu", when: Date.now() });
1403
+ // An empty explicit column projection falls back to the full declared set
1404
+ // (length-0 array is treated as "no projection", not "select nothing").
1405
+ var allOut = b.db.exportCsv({ table: "evts", columns: [] });
1406
+ check("exportCsv with an empty columns array projects all columns",
1407
+ allOut.csv.indexOf("region") !== -1 && allOut.csv.indexOf("when") !== -1);
1408
+
1409
+ // A finite ms value outside JS Date's representable range (>8.64e15) makes
1410
+ // new Date(v).toISOString() throw RangeError. exportCsv must degrade to the
1411
+ // raw numeric string, not crash the whole export.
1412
+ b.db.from("evts").insertOne({ _id: "e2", region: "us", when: 9e15 });
1413
+ var crashed = null, tsOut = null;
1414
+ try { tsOut = b.db.exportCsv({ table: "evts", timestampFields: ["when"] }); }
1415
+ catch (e) { crashed = e; }
1416
+ check("exportCsv does not crash on an out-of-range timestamp value", crashed === null);
1417
+ check("exportCsv still returns every row past the bad timestamp",
1418
+ tsOut && tsOut.rowCount === 2);
1419
+ check("an out-of-range timestamp degrades to its raw numeric string",
1420
+ tsOut && tsOut.csv.indexOf("9000000000000000") !== -1);
1421
+ } finally {
1422
+ _teardownPlain(tmpDir);
1423
+ }
1424
+ }
1425
+
1426
+ // --- declareWorm / dual-control empty-string posture rejection --------------
1427
+ async function testDeclareEmptyPosture() {
1428
+ var tmpDir = _mkTmp("db-cov-emptyposture-");
1429
+ try {
1430
+ await helpers.setupTestDb(tmpDir, [
1431
+ { name: "book", columns: { _id: "TEXT PRIMARY KEY", sym: "TEXT" } },
1432
+ ]);
1433
+
1434
+ // An empty-string posture is a distinct branch from a non-string posture:
1435
+ // typeof === "string" but length 0 must still be refused.
1436
+ var wormEmpty = await _catch(function () {
1437
+ return b.db.declareWorm({ tables: ["book"], posture: "" });
1438
+ });
1439
+ check("declareWorm empty-string posture is refused",
1440
+ wormEmpty && wormEmpty.name === "WormViolationError");
1441
+
1442
+ var dcEmpty = await _catch(function () {
1443
+ return b.db.declareRequireDualControl({ tables: ["book"], m: 2, n: 3, posture: "" });
1444
+ });
1445
+ check("declareRequireDualControl empty-string posture throws db/dual-control-bad-posture",
1446
+ dcEmpty && dcEmpty.code === "db/dual-control-bad-posture");
1447
+
1448
+ // A null posture is explicitly allowed (recorded as null) — the pass-through
1449
+ // branch of the same guard.
1450
+ var okNull = b.db.declareWorm({ tables: ["book"], posture: null });
1451
+ check("declareWorm accepts a null posture", okNull.posture === null);
1452
+ } finally {
1453
+ await helpers.teardownTestDb(tmpDir);
1454
+ }
1455
+ }
1456
+
1457
+ // --- stream(): a Buffer positional binding is a param, not an opts bag -------
1458
+ async function testStreamBufferParam() {
1459
+ var tmpDir = _mkTmp("db-cov-streambuf-");
1460
+ try {
1461
+ await _plainInit(tmpDir, [{
1462
+ name: "rows", columns: { _id: "TEXT PRIMARY KEY", blobcol: "BLOB" },
1463
+ }], { frameworkTables: false, auditSigning: false });
1464
+ b.db.from("rows").insertOne({ _id: "r1", blobcol: Buffer.from("AA") });
1465
+ b.db.from("rows").insertOne({ _id: "r2", blobcol: Buffer.from("BB") });
1466
+
1467
+ // A trailing Buffer is a SQL binding, not an options object — the last-arg
1468
+ // opts sniff excludes Buffers, so this binds as a parameter.
1469
+ var res = await _drain(b.db.stream("SELECT * FROM rows WHERE blobcol = ?", Buffer.from("AA")));
1470
+ check("stream binds a trailing Buffer as a parameter (not opts)",
1471
+ res.error === null && res.rows.length === 1 && res.rows[0]._id === "r1");
1472
+ } finally {
1473
+ _teardownPlain(tmpDir);
1474
+ }
1475
+ }
1476
+
1477
+ // --- storage-headroom probe: fault-injected + non-encrypted short-circuit --
1478
+
1479
+ async function testStorageProbeFaults() {
1480
+ // A statfs reader that THROWS must never flip the refuse-writes flag — a
1481
+ // stat error is not grounds for a self-inflicted write outage.
1482
+ var dirThrow = _mkTmp("db-cov-probe-throw-");
1483
+ try {
1484
+ await _freshVault(dirThrow);
1485
+ await b.db.init({
1486
+ dataDir: dirThrow, tmpDir: path.join(dirThrow, "tmpfs"), allowNonTmpfsTmpDir: true,
1487
+ frameworkTables: false, auditSigning: false, minFreeBytes: C.BYTES.mib(16),
1488
+ _statfsForTest: function () { throw new Error("statfs-eio"); },
1489
+ schema: [{ name: "t", columns: { _id: "TEXT PRIMARY KEY" } }],
1490
+ });
1491
+ check("storage probe swallows a throwing statfs (writes stay allowed)",
1492
+ b.db._probeStorageForTest().writesRefused === false);
1493
+ } finally { _teardownPlain(dirThrow); }
1494
+
1495
+ // A non-finite free-space reading (e.g. an overflowing bavail*bsize) is
1496
+ // ignored rather than trusted.
1497
+ var dirInf = _mkTmp("db-cov-probe-inf-");
1498
+ try {
1499
+ await _freshVault(dirInf);
1500
+ await b.db.init({
1501
+ dataDir: dirInf, tmpDir: path.join(dirInf, "tmpfs"), allowNonTmpfsTmpDir: true,
1502
+ frameworkTables: false, auditSigning: false, minFreeBytes: C.BYTES.mib(16),
1503
+ _statfsForTest: function () { return { bavail: Infinity, bsize: 1 }; },
1504
+ schema: [{ name: "t", columns: { _id: "TEXT PRIMARY KEY" } }],
1505
+ });
1506
+ check("storage probe ignores a non-finite free-space reading",
1507
+ b.db._probeStorageForTest().writesRefused === false);
1508
+ } finally { _teardownPlain(dirInf); }
1509
+
1510
+ // Plain at-rest mode short-circuits the probe entirely — the tmpfs
1511
+ // headroom guard is an encrypted-working-copy concern only.
1512
+ var dirPlain = _mkTmp("db-cov-probe-plain-");
1513
+ try {
1514
+ await _plainInit(dirPlain, [{ name: "t", columns: { _id: "TEXT PRIMARY KEY" } }],
1515
+ { frameworkTables: false, auditSigning: false });
1516
+ var p = b.db._probeStorageForTest();
1517
+ check("storage probe is a no-op under atRest:plain",
1518
+ p.writesRefused === false && p.minFreeBytes === 0);
1519
+ } finally { _teardownPlain(dirPlain); }
1520
+ }
1521
+
1522
+ // --- init() with an explicit auditSigning { mode, algorithm } --------------
1523
+
1524
+ async function testAuditSigningExplicitOpts() {
1525
+ var tmpDir = _mkTmp("db-cov-signopts-");
1526
+ try {
1527
+ // Passing an explicit auditSigning { mode, algorithm } drives the
1528
+ // opts-present arms of the signing-mode + algorithm resolution — the
1529
+ // other fixtures leave both unset and take the env / default fallbacks.
1530
+ await _freshVault(tmpDir);
1531
+ await b.db.init({
1532
+ dataDir: tmpDir, atRest: "plain",
1533
+ auditSigning: { mode: "wrapped", algorithm: "ml-dsa-65" },
1534
+ schema: [{ name: "t", columns: { _id: "TEXT PRIMARY KEY" } }],
1535
+ });
1536
+ check("init with explicit auditSigning { mode, algorithm } boots",
1537
+ b.db.getMode() === "plain");
1538
+ check("audit signing is live after explicit-opts boot",
1539
+ typeof b.auditSign.getPublicKeyFingerprint() === "string");
1540
+ } finally {
1541
+ _teardownPlain(tmpDir);
1542
+ }
1543
+ }
1544
+
1545
+ // --- init() on an already-initialized handle is an early-return no-op ------
1546
+
1547
+ async function testDoubleInit() {
1548
+ var tmpDir = _mkTmp("db-cov-reinit-");
1549
+ try {
1550
+ await _plainInit(tmpDir, [{ name: "t", columns: { _id: "TEXT PRIMARY KEY" } }],
1551
+ { frameworkTables: false, auditSigning: false });
1552
+ var pathBefore = b.db.getDbPath();
1553
+ // A second init() while initialized returns immediately — it neither
1554
+ // re-opens the handle nor reconciles the new schema.
1555
+ await b.db.init({
1556
+ dataDir: tmpDir, atRest: "plain", frameworkTables: false, auditSigning: false,
1557
+ schema: [{ name: "other", columns: { _id: "TEXT PRIMARY KEY" } }],
1558
+ });
1559
+ check("second init() leaves the db path unchanged (early return)",
1560
+ b.db.getDbPath() === pathBefore);
1561
+ check("second init() did not provision the new schema table",
1562
+ b.db.getTableMetadata("other") === null);
1563
+ } finally {
1564
+ _teardownPlain(tmpDir);
1565
+ }
1566
+ }
1567
+
1568
+ async function run() {
1569
+ await testJsonSchemaTypeAliases();
1570
+ await testMetadataBlamejsFormatAndPosture();
1571
+ await testExportCsvAdversarialInput();
1572
+ await testDeclareEmptyPosture();
1573
+ await testStreamBufferParam();
1574
+ await testInitArgValidation();
1575
+ await testNotInitializedGuard();
1576
+ await testReservedTableNames();
1577
+ await testPersonalDataCategories();
1578
+ await testMetadataAndAccessors();
1579
+ await testTransaction();
1580
+ await testExportCsv();
1581
+ await testExportCsvReservedWordTable();
1582
+ await testStream();
1583
+ await testPrepareCache();
1584
+ await testRunSql();
1585
+ await testVacuum();
1586
+ await testDeclareWorm();
1587
+ await testDualControl();
1588
+ await testEraseHard();
1589
+ await testPurgeAuditChain();
1590
+ await testHashHelpers();
1591
+ await testIntegrity();
1592
+ await testApplyPosture();
1593
+ await testCloseAndGeneration();
1594
+ await testStorageGuard();
1595
+ await testStorageProbeFaults();
1596
+ await testAuditSigningExplicitOpts();
1597
+ await testDoubleInit();
1598
+ await testTmpfsResolution();
1599
+ await testTablePrefixAndResidency();
1600
+ await testEncryptedRoundTrip();
1601
+ await testSnapshotPlain();
1602
+ await testMigrations();
1603
+ await testEraseHardLegalHold();
1604
+ await testIntegrityMonitorTick();
1605
+ await testJsonSchemaTypeMapping();
1606
+ await testExportCsvWhereProjection();
1607
+ await testLegacyKeyReseal();
1608
+ await testChainBreakDetection();
1609
+ await testRollbackDetection();
1610
+ await testWormPostureAssertion();
1611
+ await testWriteAuditTipGuard();
1612
+ }
1613
+
1614
+ module.exports = { run: run };
1615
+
1616
+ if (require.main === module) {
1617
+ run().then(
1618
+ function () { console.log("OK — " + helpers.getChecks() + " checks passed"); },
1619
+ function (e) { console.error("FAIL:", e.message, e.stack); process.exit(1); }
1620
+ );
1621
+ }