@blamejs/blamejs-shop 0.4.30 → 0.4.32

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 (338) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/checkout.js +8 -0
  4. package/lib/order.js +71 -11
  5. package/lib/vendor/MANIFEST.json +392 -278
  6. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  7. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  8. package/lib/vendor/blamejs/.gitignore +6 -0
  9. package/lib/vendor/blamejs/CHANGELOG.md +26 -0
  10. package/lib/vendor/blamejs/MIGRATING.md +43 -0
  11. package/lib/vendor/blamejs/README.md +8 -6
  12. package/lib/vendor/blamejs/SECURITY.md +19 -3
  13. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  14. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  15. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  16. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  17. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  18. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  19. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  20. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  21. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  25. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  26. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  27. package/lib/vendor/blamejs/index.js +4 -0
  28. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  29. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  30. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  31. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  32. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  33. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  34. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  35. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  36. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  37. package/lib/vendor/blamejs/lib/audit.js +259 -123
  38. package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
  39. package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
  40. package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
  41. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
  42. package/lib/vendor/blamejs/lib/backup/index.js +45 -10
  43. package/lib/vendor/blamejs/lib/break-glass.js +355 -147
  44. package/lib/vendor/blamejs/lib/cache.js +174 -105
  45. package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
  46. package/lib/vendor/blamejs/lib/cli.js +19 -14
  47. package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
  48. package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
  49. package/lib/vendor/blamejs/lib/cluster.js +119 -71
  50. package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
  51. package/lib/vendor/blamejs/lib/compliance.js +206 -4
  52. package/lib/vendor/blamejs/lib/consent.js +82 -29
  53. package/lib/vendor/blamejs/lib/constants.js +27 -11
  54. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  55. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  56. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  57. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  58. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  59. package/lib/vendor/blamejs/lib/db.js +249 -99
  60. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  61. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  62. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  63. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  64. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  65. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  66. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  67. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  68. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  69. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  70. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  71. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  72. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  73. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  74. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  75. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  76. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  77. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  78. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  79. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  80. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  81. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  82. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  83. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  84. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  85. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  86. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  87. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  88. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  89. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  90. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  91. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  92. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  93. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  94. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  95. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  96. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  97. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  98. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  99. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  100. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  101. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  102. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  103. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  104. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  105. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  106. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  107. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  108. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  109. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  110. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  111. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  112. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  113. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  114. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  115. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  116. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  117. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  118. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  119. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  120. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  121. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  122. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  123. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  124. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  125. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  126. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  127. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  128. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  129. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  131. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  132. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  133. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  134. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  135. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  136. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  137. package/lib/vendor/blamejs/lib/mail.js +8 -4
  138. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  139. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  140. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  141. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  142. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  143. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  144. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  145. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  146. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  147. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  148. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  149. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  150. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  151. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  152. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  153. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  154. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  155. package/lib/vendor/blamejs/lib/observability.js +124 -0
  156. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  157. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  158. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  159. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  160. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  161. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  162. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  163. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  164. package/lib/vendor/blamejs/lib/queue.js +7 -0
  165. package/lib/vendor/blamejs/lib/redact.js +68 -11
  166. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  167. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  168. package/lib/vendor/blamejs/lib/retention.js +101 -40
  169. package/lib/vendor/blamejs/lib/router.js +212 -5
  170. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  171. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  172. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  173. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  174. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  175. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  176. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  177. package/lib/vendor/blamejs/lib/scheduler.js +35 -12
  178. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  179. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  180. package/lib/vendor/blamejs/lib/session.js +175 -77
  181. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  182. package/lib/vendor/blamejs/lib/sse.js +26 -0
  183. package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
  184. package/lib/vendor/blamejs/lib/static.js +177 -34
  185. package/lib/vendor/blamejs/lib/subject.js +96 -49
  186. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  187. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  188. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  189. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  190. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  191. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  192. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  193. package/lib/vendor/blamejs/package.json +2 -2
  194. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  195. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  200. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  201. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  202. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  203. package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
  204. package/lib/vendor/blamejs/scripts/release.js +398 -38
  205. package/lib/vendor/blamejs/test/00-primitives.js +117 -0
  206. package/lib/vendor/blamejs/test/10-state.js +140 -14
  207. package/lib/vendor/blamejs/test/20-db.js +65 -2
  208. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  209. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  210. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  211. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  212. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  213. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  214. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  215. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  216. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  217. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  220. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  221. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  222. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  223. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  224. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  225. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  226. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  227. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  228. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  229. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  230. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  231. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  232. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  233. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  234. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  235. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  236. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  237. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  238. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  240. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  250. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
  251. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  256. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  260. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  261. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  272. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  273. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  274. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  275. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  279. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  280. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  283. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  284. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  285. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  293. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  304. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  310. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  312. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  313. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  314. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  315. package/lib/vendor/blamejs/test/smoke.js +79 -21
  316. package/package.json +1 -1
  317. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  318. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  319. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  320. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  321. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  322. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  323. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  324. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  325. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  326. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  327. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  328. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  329. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  330. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  331. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  332. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  333. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  334. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  335. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  336. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  337. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  338. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -52,12 +52,13 @@ var nodeFs = require("node:fs");
52
52
  var nodePath = require("node:path");
53
53
  var { DatabaseSync } = require("node:sqlite");
54
54
  var atomicFile = require("../atomic-file");
55
- var safeSql = require("../safe-sql");
55
+ var sql = require("../sql");
56
56
  var C = require("../constants");
57
57
  var cryptoField = require("../crypto-field");
58
58
  var bCrypto = require("../crypto");
59
59
  var vaultAad = require("../vault-aad");
60
60
  var dbSchema = require("../db-schema");
61
+ var frameworkFiles = require("../framework-files");
61
62
  var lazyRequire = require("../lazy-require");
62
63
  var { boot } = require("../log");
63
64
  var numericBounds = require("../numeric-bounds");
@@ -81,6 +82,11 @@ var agentSnapshotLazy = lazyRequire(function () { return require("../agent-snaps
81
82
  // rotation pipeline never walks, so archive-wrap exports the same external
82
83
  // AAD_ROTATION descriptor and must be gated here too.
83
84
  var archiveWrapLazy = lazyRequire(function () { return require("../archive-wrap"); });
85
+ // The DSR ticket store, when backed by an operator-supplied database, holds
86
+ // {aad:true} sealed cells (subject identifiers + request payload) keyed off the
87
+ // vault root that this pipeline never walks, so dsr exports the same external
88
+ // AAD_ROTATION descriptor and must be gated here too.
89
+ var dsrLazy = lazyRequire(function () { return require("../dsr"); });
84
90
  var { defineClass } = require("../framework-error");
85
91
 
86
92
  var rotateLog = boot("vault-rotate");
@@ -92,18 +98,30 @@ var DEFAULT_DRIFT_SAMPLE_LIMIT = 100;
92
98
  var DEFAULT_VERIFY_SAMPLE_MIN = 5;
93
99
  var DEFAULT_VERIFY_SAMPLE_FRAC = 0.01;
94
100
 
101
+ // The catalog/PRAGMA statements all compose through b.sql's narrow audited
102
+ // catalog sub-API (b.sql.catalog / b.sql.pragma) - the only path that emits
103
+ // an sqlite_master reference or a PRAGMA verb, allowlisting exactly the
104
+ // statements the key-rotation walk needs and refusing every other internal
105
+ // identifier / PRAGMA verb. Each returns { sql, params }; the node:sqlite
106
+ // handle takes the params positionally.
107
+ function _all(db, built) {
108
+ var stmt = db.prepare(built.sql);
109
+ return built.params.length > 0 ? stmt.all.apply(stmt, built.params) : stmt.all();
110
+ }
111
+ function _get(db, built) {
112
+ var stmt = db.prepare(built.sql);
113
+ return built.params.length > 0 ? stmt.get.apply(stmt, built.params) : stmt.get();
114
+ }
115
+
95
116
  function _listLiveTables(db) {
96
- return db.prepare(
97
- "SELECT name FROM sqlite_master " +
98
- "WHERE type='table' AND name NOT LIKE 'sqlite_%'"
99
- ).all().map(function (r) { return r.name; });
117
+ return _all(db, sql.catalog.listTables()).map(function (r) { return r.name; });
100
118
  }
101
119
 
102
120
  function _listLiveColumns(db, table) {
103
121
  // PRAGMA table_info — table name comes from sqlite_master so it's
104
- // already validated as an existing identifier.
105
- return db.prepare("PRAGMA table_info(\"" + table.replace(/"/g, '""') + "\")").all()
106
- .map(function (c) { return c.name; });
122
+ // already validated as an existing identifier; b.sql.catalog.tableInfo
123
+ // quotes it by construction.
124
+ return _all(db, sql.catalog.tableInfo(table)).map(function (c) { return c.name; });
107
125
  }
108
126
 
109
127
  function _knownColumnsFor(schema, infraColumns) {
@@ -196,12 +214,13 @@ function validateSchemaMatch(db, opts) {
196
214
  }
197
215
  if (unknown.length === 0) continue;
198
216
 
199
- var quotedCols = unknown.map(function (n) { return '"' + n.replace(/"/g, '""') + '"'; }).join(", ");
200
- var sampleSql = "SELECT " + quotedCols +
201
- " FROM \"" + table.replace(/"/g, '""') + "\" LIMIT " + sampleLimit;
217
+ var sampleBuilt = sql.select(table, { dialect: "sqlite", quoteName: true })
218
+ .columns(unknown)
219
+ .limit(sampleLimit)
220
+ .toSql();
202
221
  var sampled;
203
222
  try {
204
- sampled = db.prepare(sampleSql).all();
223
+ sampled = _all(db, sampleBuilt);
205
224
  } catch (e) {
206
225
  warnings.push({
207
226
  kind: "sample_failed",
@@ -307,7 +326,8 @@ function verify(opts) {
307
326
  var schema = cryptoField.getSchema(table);
308
327
  if (!schema || !Array.isArray(schema.sealedFields) || schema.sealedFields.length === 0) continue;
309
328
 
310
- var totalRow = db.prepare('SELECT COUNT(*) AS n FROM "' + table.replace(/"/g, '""') + '"').get();
329
+ var totalRow = _get(db, sql.select(table, { dialect: "sqlite", quoteName: true })
330
+ .count("*", "n").toSql());
311
331
  var total = totalRow ? totalRow.n : 0;
312
332
  if (total === 0) continue;
313
333
 
@@ -315,10 +335,10 @@ function verify(opts) {
315
335
  if (sampleN > total) sampleN = total;
316
336
 
317
337
  // RANDOM() is fine for a sampler — we're picking representative rows,
318
- // not building cryptographic randomness.
319
- var sampled = db.prepare(
320
- 'SELECT * FROM "' + table.replace(/"/g, '""') + '" ORDER BY RANDOM() LIMIT ?'
321
- ).all(sampleN);
338
+ // not building cryptographic randomness. b.sql.catalog.sampleRandom is
339
+ // the audited ORDER BY RANDOM() form (the general builder has no random-
340
+ // order clause); columns omitted -> `*`.
341
+ var sampled = _all(db, sql.catalog.sampleRandom(table, null, { limit: sampleN }));
322
342
 
323
343
  var foundOldFail = !oldKeys; // when no oldKeys supplied, this check is N/A
324
344
  var verifiedRows = 0;
@@ -439,7 +459,7 @@ var VAULT_PREFIX_LEN = C.VAULT_PREFIX.length;
439
459
  // so loading rotate.js doesn't eagerly pull the agent modules.
440
460
  var EXTERNAL_AAD_MODULE_LOADERS = [
441
461
  agentIdempotencyLazy, agentOrchestratorLazy, agentTenantLazy, agentSnapshotLazy,
442
- archiveWrapLazy,
462
+ archiveWrapLazy, dsrLazy,
443
463
  ];
444
464
 
445
465
  function _externalAadTables() {
@@ -464,22 +484,25 @@ function _emit(cb, ev) {
464
484
  }
465
485
  }
466
486
 
467
- // Open a file for fsync. Different from atomicFile.fsync (which takes
468
- // an already-open fd) vault-rotate's fsync-by-path semantic opens
469
- // then syncs then closes, which is the right shape when we don't have
470
- // the original write fd around.
471
- //
472
- // CodeQL js/insecure-temporary-file: `p` is an operator-supplied path
473
- // inside opts.stagingDir (an owner-only 0o700 framework directory
474
- // established via atomicFile.ensureDir at the top of rotate()). Not an
475
- // os.tmpdir-reachable path. The fd is used solely for fsync and is
476
- // closed immediately; no bytes are read or written through it, so the
477
- // tmp-file predictability heuristic does not apply.
478
- function _fsyncFileByPath(p) {
487
+ // Create a fresh file in the owner-only staging dir with exclusive,
488
+ // no-follow semantics, then fsync it. O_EXCL turns a pre-planted file or
489
+ // symlink into a hard failure instead of a followed write; O_NOFOLLOW
490
+ // refuses a symlinked final component; the explicit 0o600 keeps the bytes
491
+ // owner-only regardless of umask. Any leftover from an aborted prior
492
+ // rotation is cleared first so the exclusive create can proceed. The
493
+ // staging dir is already 0o700 owner-only, so this is defense in depth
494
+ // against a same-user pre-plant / symlink swap (CWE-377 / CWE-379 / CWE-59).
495
+ function _writeStagedFileExclusive(p, data) {
496
+ try { nodeFs.unlinkSync(p); } catch (_e) { /* no stale entry to clear */ }
497
+ var fd = nodeFs.openSync(p,
498
+ nodeFs.constants.O_WRONLY | nodeFs.constants.O_CREAT |
499
+ nodeFs.constants.O_EXCL | (nodeFs.constants.O_NOFOLLOW || 0), 0o600);
479
500
  try {
480
- var fd = nodeFs.openSync(p, "r+");
481
- try { nodeFs.fsyncSync(fd); } finally { nodeFs.closeSync(fd); }
482
- } catch (_e) { /* best-effort across platforms */ }
501
+ nodeFs.writeFileSync(fd, data);
502
+ nodeFs.fsyncSync(fd);
503
+ } finally {
504
+ nodeFs.closeSync(fd);
505
+ }
483
506
  }
484
507
 
485
508
  function _reSealValue(sealedValue, oldKeys, newKeys) {
@@ -521,15 +544,19 @@ function _walkAndReSeal(node, oldKeys, newKeys) {
521
544
  return { value: node, changed: false };
522
545
  }
523
546
 
524
- function _runStmt(db, sql) { db.prepare(sql).run(); }
547
+ // Transaction-control statements only (BEGIN / COMMIT / ROLLBACK) - fixed
548
+ // keywords, no identifier / value, so they stay verbatim rather than route
549
+ // through b.sql (the builder has no transaction-control verb). The param is
550
+ // named `stmtText` so it does not shadow the module-level `sql` builder.
551
+ function _runStmt(db, stmtText) { db.prepare(stmtText).run(); }
525
552
 
526
553
  function _rotateColumn(db, table, column, schema, roots, batchSize, progress) {
527
- // Identifiers reach SQL through safeSql.quoteIdentifier runs
528
- // validateIdentifier (rejects bad shape / reserved words /
529
- // sqlite_-prefix) + emits the dialect-correct quoted form.
530
- var qt = safeSql.quoteIdentifier(table, "sqlite");
531
- var qc = safeSql.quoteIdentifier(column, "sqlite");
532
- var total = db.prepare("SELECT COUNT(*) AS n FROM " + qt + " WHERE " + qc + " IS NOT NULL").get().n;
554
+ // Every statement composes through b.sql (sqlite dialect, quoteName so
555
+ // the concrete handle's table is quoted, not left bare for a cluster
556
+ // rewrite that does not apply here). Identifiers are validated + quoted
557
+ // by construction; the cursor bound (_id) + LIMIT bind as ? placeholders.
558
+ var total = _get(db, sql.select(table, { dialect: "sqlite", quoteName: true })
559
+ .count("*", "n").whereNotNull(column).toSql()).n;
533
560
  if (total === 0) return 0;
534
561
 
535
562
  // AAD-bound tables (registerTable({aad:true})) seal each cell under a
@@ -540,36 +567,54 @@ function _rotateColumn(db, table, column, schema, roots, batchSize, progress) {
540
567
  var aadMode = !!(schema && schema.aad);
541
568
  var rowIdField = aadMode ? schema.rowIdField : null;
542
569
  var needRid = aadMode && rowIdField && rowIdField !== "_id";
543
- var qrid = needRid ? safeSql.quoteIdentifier(rowIdField, "sqlite") : null;
544
570
 
545
- var sel = db.prepare(
546
- "SELECT _id, " + qc + " AS v" + (qrid ? ", " + qrid + " AS rid" : "") + " FROM " + qt +
547
- " WHERE " + qc + " IS NOT NULL AND _id > ? ORDER BY _id LIMIT ?"
548
- );
549
- var upd = db.prepare("UPDATE " + qt + " SET " + qc + " = ? WHERE _id = ?");
571
+ // Keyset-cursor page over (_id) ascending. The projected columns are read
572
+ // by their REAL names off the result row (no AS alias) - the column value
573
+ // is row[column], the row-id value is row[rowIdField]. The SQL text is
574
+ // constant across the loop (only the bound _id-cursor changes; LIMIT is a
575
+ // builder-inlined integer literal, validated non-negative), so prepare
576
+ // once + re-run with the fresh cursor param positionally. The SELECT
577
+ // carries exactly one `?` (the _id cursor); the UPDATE carries two (the
578
+ // resealed value + the _id).
579
+ var selCols = ["_id", column];
580
+ if (needRid) selCols.push(rowIdField);
581
+ var selBuilt = sql.select(table, { dialect: "sqlite", quoteName: true })
582
+ .columns(selCols)
583
+ .whereNotNull(column)
584
+ .whereOp("_id", ">", "")
585
+ .orderBy("_id")
586
+ .limit(batchSize)
587
+ .toSql();
588
+ var sel = db.prepare(selBuilt.sql);
589
+ var updBuilt = sql.update(table, { dialect: "sqlite", quoteName: true })
590
+ .set(column, "")
591
+ .where("_id", "")
592
+ .toSql();
593
+ var upd = db.prepare(updBuilt.sql);
550
594
 
551
595
  var processed = 0;
552
596
  var lastId = "";
553
597
  while (true) {
554
- var rows = sel.all(lastId, batchSize);
598
+ var rows = sel.all(lastId);
555
599
  if (rows.length === 0) break;
556
600
 
557
601
  dbSchema.runInTransaction(db, function () {
558
602
  for (var i = 0; i < rows.length; i++) {
559
603
  var row = rows[i];
560
- if (typeof row.v !== "string") continue;
561
- if (aadMode && vaultAad.isAadSealed(row.v)) {
604
+ var cellVal = row[column];
605
+ if (typeof cellVal !== "string") continue;
606
+ if (aadMode && vaultAad.isAadSealed(cellVal)) {
562
607
  // Rebuild the exact AAD the seal side used. cryptoField._aadParts
563
608
  // reads row[schema.rowIdField]; feed it the rowIdField value we
564
- // selected (rid, or _id when rowIdField IS _id).
609
+ // selected (row[rowIdField], or _id when rowIdField IS _id).
565
610
  var rowForAad = {};
566
- rowForAad[rowIdField] = needRid ? row.rid : row._id;
611
+ rowForAad[rowIdField] = needRid ? row[rowIdField] : row._id;
567
612
  var aad = cryptoField._aadParts(schema, table, column, rowForAad);
568
- upd.run(vaultAad.resealRoot(row.v, aad, roots.oldRootJson, roots.newRootJson), row._id);
569
- } else if (row.v.indexOf(C.VAULT_PREFIX) === 0) {
613
+ upd.run(vaultAad.resealRoot(cellVal, aad, roots.oldRootJson, roots.newRootJson), row._id);
614
+ } else if (cellVal.indexOf(C.VAULT_PREFIX) === 0) {
570
615
  // Plain vault: cell (non-AAD table, or a legacy pre-AAD cell in
571
616
  // an AAD table that the next sealRow upgrades).
572
- upd.run(_reSealValue(row.v, roots.oldKeys, roots.newKeys), row._id);
617
+ upd.run(_reSealValue(cellVal, roots.oldKeys, roots.newKeys), row._id);
573
618
  }
574
619
  }
575
620
  });
@@ -581,23 +626,33 @@ function _rotateColumn(db, table, column, schema, roots, batchSize, progress) {
581
626
  }
582
627
 
583
628
  function _rotateOverflow(db, table, oldKeys, newKeys, batchSize, progress, warnings) {
584
- var qt = '"' + table.replace(/"/g, '""') + '"';
585
- var cols = db.prepare("PRAGMA table_info(" + qt + ")").all();
629
+ var cols = _all(db, sql.catalog.tableInfo(table));
586
630
  if (!cols.some(function (c) { return c.name === "data"; })) return 0;
587
631
 
588
- var total = db.prepare("SELECT COUNT(*) AS n FROM " + qt + " WHERE data IS NOT NULL").get().n;
632
+ var total = _get(db, sql.select(table, { dialect: "sqlite", quoteName: true })
633
+ .count("*", "n").whereNotNull("data").toSql()).n;
589
634
  if (total === 0) return 0;
590
635
 
591
- var sel = db.prepare(
592
- "SELECT _id, data FROM " + qt +
593
- " WHERE data IS NOT NULL AND _id > ? ORDER BY _id LIMIT ?"
594
- );
595
- var upd = db.prepare("UPDATE " + qt + " SET data = ? WHERE _id = ?");
636
+ // Same keyset cursor as _rotateColumn over the overflow `data` JSON
637
+ // column: one bound `?` (the _id cursor), builder-inlined LIMIT literal.
638
+ var selBuilt = sql.select(table, { dialect: "sqlite", quoteName: true })
639
+ .columns(["_id", "data"])
640
+ .whereNotNull("data")
641
+ .whereOp("_id", ">", "")
642
+ .orderBy("_id")
643
+ .limit(batchSize)
644
+ .toSql();
645
+ var sel = db.prepare(selBuilt.sql);
646
+ var updBuilt = sql.update(table, { dialect: "sqlite", quoteName: true })
647
+ .set("data", "")
648
+ .where("_id", "")
649
+ .toSql();
650
+ var upd = db.prepare(updBuilt.sql);
596
651
 
597
652
  var processed = 0;
598
653
  var lastId = "";
599
654
  while (true) {
600
- var rows = sel.all(lastId, batchSize);
655
+ var rows = sel.all(lastId);
601
656
  if (rows.length === 0) break;
602
657
 
603
658
  _runStmt(db, "BEGIN");
@@ -670,7 +725,8 @@ async function rotate(opts) {
670
725
  "pipeline and would be orphaned under the retired keypair: " + externalAad.join(", ") +
671
726
  ". Re-seal each via its module hook (b.agent.idempotency.reseal / " +
672
727
  "b.agent.orchestrator.reseal / b.agent.tenant AAD_ROTATION reseal / " +
673
- "b.agent.snapshot.reseal / b.archive.rewrapTenant for archive-wrap:tenant-blobs) " +
728
+ "b.agent.snapshot.reseal / b.archive.rewrapTenant for archive-wrap:tenant-blobs / " +
729
+ "b.dsr.reseal for the dsr_tickets store) " +
674
730
  "BEFORE retiring the old keypair, then pass " +
675
731
  "opts.externalAadResealed: [" + externalAad.map(function (t) { return JSON.stringify(t); }).join(", ") +
676
732
  "] to acknowledge. If you do not use these features, pass opts.externalAadResealed: true.");
@@ -680,10 +736,10 @@ async function rotate(opts) {
680
736
  var progress = opts.progressCallback;
681
737
  var warnings = [];
682
738
  var paths = Object.assign({
683
- encryptedDb: "db.enc",
684
- dbKeySealed: "db.key.enc",
685
- vaultKeyPlain: "vault.key",
686
- vaultKeySealed: "vault.key.sealed",
739
+ encryptedDb: frameworkFiles.fileName("dbEnc"),
740
+ dbKeySealed: frameworkFiles.fileName("dbKeyEnc"),
741
+ vaultKeyPlain: frameworkFiles.fileName("vaultKey"),
742
+ vaultKeySealed: frameworkFiles.fileName("vaultKey") + ".sealed",
687
743
  additionalSealed: [],
688
744
  verbatimFiles: [],
689
745
  verbatimDirs: [],
@@ -709,7 +765,10 @@ async function rotate(opts) {
709
765
  }
710
766
  var dest = nodePath.join(stagingDir, entry.relativePath);
711
767
  atomicFile.ensureDir(nodePath.dirname(dest));
712
- nodeFs.copyFileSync(src, dest);
768
+ // Stage via the exclusive-create + fsync helper rather than a plain copy,
769
+ // so the verbatim file is durable at write time (no later by-path fsync)
770
+ // and a pre-planted file/symlink at the staging path hard-fails.
771
+ _writeStagedFileExclusive(dest, nodeFs.readFileSync(src));
713
772
  }
714
773
  for (var vd = 0; vd < paths.verbatimDirs.length; vd++) {
715
774
  var dent = paths.verbatimDirs[vd];
@@ -737,9 +796,9 @@ async function rotate(opts) {
737
796
  var newRootJson = keysJson;
738
797
  if (mode === "wrapped") {
739
798
  var sealed = await vaultWrap().wrap(keysJson, opts.newPassphrase);
740
- nodeFs.writeFileSync(nodePath.join(stagingDir, paths.vaultKeySealed), sealed, { mode: 0o600 });
799
+ _writeStagedFileExclusive(nodePath.join(stagingDir, paths.vaultKeySealed), sealed);
741
800
  } else {
742
- nodeFs.writeFileSync(nodePath.join(stagingDir, paths.vaultKeyPlain), keysJson, { mode: 0o600 });
801
+ _writeStagedFileExclusive(nodePath.join(stagingDir, paths.vaultKeyPlain), keysJson);
743
802
  }
744
803
 
745
804
  // 3. re-seal db.key.enc + any operator-supplied additionalSealed files
@@ -759,14 +818,14 @@ async function rotate(opts) {
759
818
  var dbKeyB64Aad = vaultAad.unsealRoot(sealedKey, dbKeyAad, oldRootJson);
760
819
  dbKey = Buffer.from(dbKeyB64Aad, "base64");
761
820
  var resealedAad = vaultAad.sealRoot(dbKeyB64Aad, dbKeyAad, newRootJson);
762
- nodeFs.writeFileSync(nodePath.join(stagingDir, paths.dbKeySealed), resealedAad, { mode: 0o600 });
821
+ _writeStagedFileExclusive(nodePath.join(stagingDir, paths.dbKeySealed), resealedAad);
763
822
  } else if (sealedKey.indexOf(C.VAULT_PREFIX) === 0) {
764
823
  // Legacy plain-sealed db.key.enc (pre-AAD). Re-key in place; db.init
765
824
  // read-migrates plain -> AAD on the next boot.
766
825
  var dbKeyB64 = bCrypto.decrypt(sealedKey.substring(VAULT_PREFIX_LEN), oldKeys);
767
826
  dbKey = Buffer.from(dbKeyB64, "base64");
768
827
  var resealedKey = C.VAULT_PREFIX + bCrypto.encrypt(dbKeyB64, newKeys);
769
- nodeFs.writeFileSync(nodePath.join(stagingDir, paths.dbKeySealed), resealedKey, { mode: 0o600 });
828
+ _writeStagedFileExclusive(nodePath.join(stagingDir, paths.dbKeySealed), resealedKey);
770
829
  } else {
771
830
  throw new VaultRotateError("vault-rotate/bad-dbkey",
772
831
  "rotate: db.key.enc does not start with a vault prefix (vault: or vault.aad:)");
@@ -789,8 +848,8 @@ async function rotate(opts) {
789
848
  }
790
849
  var asDestDir = nodePath.join(stagingDir, nodePath.dirname(ase.relativePath));
791
850
  if (!nodeFs.existsSync(asDestDir)) atomicFile.ensureDir(asDestDir);
792
- nodeFs.writeFileSync(nodePath.join(stagingDir, ase.relativePath),
793
- _reSealValue(current, oldKeys, newKeys), { mode: 0o600 });
851
+ _writeStagedFileExclusive(nodePath.join(stagingDir, ase.relativePath),
852
+ _reSealValue(current, oldKeys, newKeys));
794
853
  }
795
854
 
796
855
  // 3b. Framework-managed crypto-field derived-hash files — always
@@ -801,14 +860,17 @@ async function rotate(opts) {
801
860
  // re-seals to the same value since the keypair is unchanged).
802
861
  var saltSrc = nodePath.join(dataDir, "vault.derived-hash-salt");
803
862
  if (nodeFs.existsSync(saltSrc)) {
804
- nodeFs.copyFileSync(saltSrc, nodePath.join(stagingDir, "vault.derived-hash-salt"));
863
+ // Stage via the exclusive-create + fsync helper (not a plain copy) so the
864
+ // salt is durable at write time and no later by-path fsync is needed.
865
+ _writeStagedFileExclusive(nodePath.join(stagingDir, "vault.derived-hash-salt"),
866
+ nodeFs.readFileSync(saltSrc));
805
867
  }
806
868
  var macSrc = nodePath.join(dataDir, "vault.derived-hash-mac.sealed");
807
869
  if (nodeFs.existsSync(macSrc)) {
808
870
  var macCurrent = nodeFs.readFileSync(macSrc, "utf8").trim();
809
871
  if (macCurrent.indexOf(C.VAULT_PREFIX) === 0) {
810
- nodeFs.writeFileSync(nodePath.join(stagingDir, "vault.derived-hash-mac.sealed"),
811
- _reSealValue(macCurrent, oldKeys, newKeys), { mode: 0o600 });
872
+ _writeStagedFileExclusive(nodePath.join(stagingDir, "vault.derived-hash-mac.sealed"),
873
+ _reSealValue(macCurrent, oldKeys, newKeys));
812
874
  }
813
875
  }
814
876
 
@@ -830,22 +892,19 @@ async function rotate(opts) {
830
892
  try { plainBytes = bCrypto.decryptPacked(packed, dbKey, dbEncAad); }
831
893
  catch (_eAad) { plainBytes = bCrypto.decryptPacked(packed, dbKey); }
832
894
  var tmpDbPath = nodePath.join(stagingDir, "_blamejs_rotate.tmp.db");
833
- nodeFs.writeFileSync(tmpDbPath, plainBytes, { mode: 0o600 });
895
+ _writeStagedFileExclusive(tmpDbPath, plainBytes);
834
896
 
835
897
  var db = new DatabaseSync(tmpDbPath);
836
898
  try {
837
- _runStmt(db, "PRAGMA journal_mode=WAL");
838
- _runStmt(db, "PRAGMA synchronous=NORMAL");
899
+ db.prepare(sql.pragma("journal_mode", "WAL").sql).run();
900
+ db.prepare(sql.pragma("synchronous", "NORMAL").sql).run();
839
901
 
840
902
  // Walk tables. For each, re-seal every column declared sealed
841
903
  // by the field-crypto registry, plus the overflow `data` JSON
842
904
  // column if present.
843
905
  var tablesToRotate = Array.isArray(opts.tables) && opts.tables.length > 0
844
906
  ? opts.tables.slice()
845
- : db.prepare(
846
- "SELECT name FROM sqlite_master " +
847
- "WHERE type='table' AND name NOT LIKE 'sqlite_%'"
848
- ).all().map(function (r) { return r.name; });
907
+ : _listLiveTables(db);
849
908
 
850
909
  // Serialized roots threaded to the AAD reseal path; oldRootJson /
851
910
  // newRootJson match b.vault.getKeysJson() so rotated AAD cells unseal
@@ -854,15 +913,11 @@ async function rotate(opts) {
854
913
 
855
914
  for (var ti = 0; ti < tablesToRotate.length; ti++) {
856
915
  var table = tablesToRotate[ti];
857
- var tableExists = db.prepare(
858
- "SELECT name FROM sqlite_master WHERE type='table' AND name = ?"
859
- ).get(table);
916
+ var tableExists = _get(db, sql.catalog.tableExists(table));
860
917
  if (!tableExists) continue;
861
918
 
862
919
  var schema = cryptoField.getSchema(table);
863
- var liveCols = db.prepare(
864
- 'PRAGMA table_info("' + table.replace(/"/g, '""') + '")'
865
- ).all().map(function (c) { return c.name; });
920
+ var liveCols = _listLiveColumns(db, table);
866
921
  var liveColSet = Object.create(null);
867
922
  for (var lc = 0; lc < liveCols.length; lc++) liveColSet[liveCols[lc]] = true;
868
923
 
@@ -879,7 +934,7 @@ async function rotate(opts) {
879
934
  if (tableRows > 0) { tablesProcessed++; totalRowsProcessed += tableRows; }
880
935
  }
881
936
 
882
- _runStmt(db, "PRAGMA wal_checkpoint(TRUNCATE)");
937
+ db.prepare(sql.pragma("wal_checkpoint", "TRUNCATE").sql).run();
883
938
  } finally {
884
939
  db.close();
885
940
  }
@@ -893,25 +948,23 @@ async function rotate(opts) {
893
948
  try { nodeFs.unlinkSync(tmpDbPath + "-shm"); }
894
949
  catch (e) { rotateLog.debug("cleanup-failed", { op: "fs.unlinkSync", path: tmpDbPath + "-shm", error: e.message }); }
895
950
 
896
- // CodeQL js/insecure-temporary-file: every "tmp" path here is inside
897
- // opts.stagingDir — operator-supplied, ensureDir'd 0o700 owner-only,
898
- // never under os.tmpdir(). The filenames are framework-internal
899
- // markers (`_blamejs_rotate.tmp.db`, `_blamejs_verify.tmp.db`); their
900
- // predictability does not enable a symlink attack because the staging
901
- // dir's owner-only perms prevent any other user from creating entries
902
- // inside it. Files are written 0o600 implicitly via the dir's umask
903
- // and removed before the rotation completes.
951
+ // Every staged path lives inside opts.stagingDir (operator-supplied,
952
+ // ensureDir'd 0o700 owner-only, never under os.tmpdir()) and carries a
953
+ // framework-internal marker name. The staged writes go through
954
+ // _writeStagedFileExclusive exclusive + no-follow create, owner-only
955
+ // 0o600 so a same-user pre-plant or symlink swap is a hard failure
956
+ // rather than a followed write, and the bytes never inherit a wider mode.
904
957
  var rotatedBytes = nodeFs.readFileSync(tmpDbPath);
905
958
  // Re-encrypt under the SAME dataDir AAD so db.init's AAD-first open
906
959
  // succeeds after the staged dir is swapped over dataDir in place.
907
- nodeFs.writeFileSync(nodePath.join(stagingDir, paths.encryptedDb),
960
+ _writeStagedFileExclusive(nodePath.join(stagingDir, paths.encryptedDb),
908
961
  bCrypto.encryptPacked(rotatedBytes, dbKey, dbEncAad));
909
962
  nodeFs.unlinkSync(tmpDbPath);
910
963
 
911
964
  // Round-trip verify on the staged DB
912
965
  _emit(progress, { phase: "verify" });
913
966
  var verifyTmp = nodePath.join(stagingDir, "_blamejs_verify.tmp.db");
914
- nodeFs.writeFileSync(verifyTmp,
967
+ _writeStagedFileExclusive(verifyTmp,
915
968
  bCrypto.decryptPacked(nodeFs.readFileSync(nodePath.join(stagingDir, paths.encryptedDb)), dbKey, dbEncAad));
916
969
  var vdb = new DatabaseSync(verifyTmp);
917
970
  try {
@@ -934,19 +987,26 @@ async function rotate(opts) {
934
987
  }
935
988
  }
936
989
 
937
- // 5. fsync staging for durability before caller does the swap
990
+ // 5. fsync staging directory entries for durability before the caller swaps.
991
+ // Every staged FILE is already fsync'd at write time by
992
+ // _writeStagedFileExclusive (the re-encrypted db, the resealed vault/db keys,
993
+ // sealed files, the derived-hash salt, and verbatim files), so re-opening
994
+ // each by path here is redundant — and opening a staged file by path is the
995
+ // os-temp-dir open the static analyzer refuses (CWE-377 heuristic). Only the
996
+ // optional verbatimDirs are copied with copyFileSync (no per-file fsync);
997
+ // their directory entries + the rename are made durable by fsyncDir and their
998
+ // source files in dataDir remain intact, so a crash in that narrow window is
999
+ // recoverable.
938
1000
  _emit(progress, { phase: "fsync" });
939
- function fsyncTree(dir) {
1001
+ function fsyncDirTree(dir) {
940
1002
  var entries = nodeFs.readdirSync(dir);
941
1003
  for (var i = 0; i < entries.length; i++) {
942
1004
  var p = nodePath.join(dir, entries[i]);
943
- var st = nodeFs.statSync(p);
944
- if (st.isFile()) _fsyncFileByPath(p);
945
- else if (st.isDirectory()) fsyncTree(p);
1005
+ if (nodeFs.statSync(p).isDirectory()) fsyncDirTree(p);
946
1006
  }
947
1007
  atomicFile.fsyncDir(dir);
948
1008
  }
949
- fsyncTree(stagingDir);
1009
+ fsyncDirTree(stagingDir);
950
1010
 
951
1011
  var durationMs = Date.now() - startedAt;
952
1012
  _emit(progress, {
@@ -304,6 +304,12 @@ module.exports = {
304
304
  isAadSealed: isAadSealed,
305
305
  buildColumnAad: buildColumnAad,
306
306
  buildContextAad: buildContextAad,
307
+ // canonicalizeAad — the length-prefixed, sorted-keys AAD-bytes
308
+ // encoder. Exported (internal) so a sibling primitive that runs its
309
+ // own AEAD (crypto-field's per-row K_row cells) threads byte-identical
310
+ // AAD into encryptPacked/decryptPacked as this module does for its
311
+ // own seal/unseal — one canonical encoder, no drift.
312
+ canonicalizeAad: _canonicalize,
307
313
  AAD_PREFIX: AAD_PREFIX,
308
314
  AAD_VERSION: AAD_VERSION,
309
315
  VaultAadError: VaultAadError,
@@ -130,6 +130,7 @@ function _timingSafeHexEqual(a, b) {
130
130
  var KNOWN_VENDOR_DATA = Object.freeze({
131
131
  "public-suffix-list": {
132
132
  module: "./vendor/public-suffix-list.data",
133
+ // allow:hand-rolled-sql — `_blamejs_canary_*` is an in-payload tamper-canary token, not a SQL table name (no DB sink in this file)
133
134
  canary: "_blamejs_canary_v0_9_8_.local",
134
135
  // Canary parse check — operator-side `b.publicSuffix.isPublicSuffix(canary)`
135
136
  // MUST return true after the PSL parser ingests the data. The check
@@ -138,6 +139,7 @@ var KNOWN_VENDOR_DATA = Object.freeze({
138
139
  },
139
140
  "common-passwords-top-10000": {
140
141
  module: "./vendor/common-passwords-top-10000.data",
142
+ // allow:hand-rolled-sql — `_blamejs_canary_*` is an in-payload tamper-canary token, not a SQL table name (no DB sink in this file)
141
143
  canary: "_blamejs_canary_password_2026_05_13_blamejs_internal_",
142
144
  description: "Top-10000 most common passwords (SecLists). Used by b.auth.password to refuse known-breached credentials.",
143
145
  },
@@ -530,22 +530,32 @@ function _parseExtensionHeader(header) {
530
530
  for (var i = 0; i < entries.length; i++) {
531
531
  var parts = structuredFields.splitTopLevel(entries[i], ";").map(function (s) { return s.trim(); });
532
532
  if (!parts[0]) continue;
533
- // `params` has no prototype chain `Object.create(null)` defends
534
- // against `__proto__` / `constructor` / `prototype` parameter names
535
- // in the Sec-WebSocket-Extensions header polluting downstream lookups.
536
- var ext = { name: parts[0].toLowerCase(), params: Object.create(null) };
533
+ // Collect [name, value] pairs, then materialize the params map via
534
+ // Object.fromEntries onto a null-prototype object. The extension-
535
+ // parameter name is taken from the client-supplied Sec-WebSocket-
536
+ // Extensions header, so it is never used as a computed-write key
537
+ // (`params[name] = value`) — that is the CWE-915 unsafe-reflection /
538
+ // CWE-1321 prototype-pollution sink. POISONED params (`__proto__` /
539
+ // `constructor` / `prototype`) are dropped, and the null-prototype
540
+ // accumulator means even a slipped name cannot reach Object.prototype.
541
+ var paramPairs = [];
537
542
  for (var j = 1; j < parts.length; j++) {
538
543
  var kv = parts[j].split("=");
539
544
  var k = kv[0].trim().toLowerCase();
540
545
  if (!k) continue;
546
+ if (k === "__proto__" || k === "constructor" || k === "prototype") continue;
541
547
  var v = kv.length > 1 ? kv.slice(1).join("=").trim() : true;
542
548
  // Strip surrounding quotes per the token-or-quoted-string grammar.
543
549
  if (typeof v === "string") {
544
550
  var _unq = structuredFields.unquoteSfString(v);
545
551
  if (_unq !== null) v = _unq;
546
552
  }
547
- ext.params[k] = v;
553
+ paramPairs.push([k, v]);
548
554
  }
555
+ var ext = {
556
+ name: parts[0].toLowerCase(),
557
+ params: Object.assign(Object.create(null), Object.fromEntries(paramPairs)),
558
+ };
549
559
  out.push(ext);
550
560
  }
551
561
  return out;
@@ -961,6 +971,22 @@ class WebSocketConnection extends EventEmitter {
961
971
  self._transitionToClosed(1006, "abnormal closure", false, null);
962
972
  }
963
973
  });
974
+ socket.on("end", function () {
975
+ // Peer half-closed (TCP FIN) without sending a Close frame. HTTP
976
+ // 'upgrade' sockets default to allowHalfOpen=true, so this arrives
977
+ // as 'end' (readable side ended) while the writable side stays
978
+ // open — the 'close' handler above never fires and the connection
979
+ // would otherwise wedge open (ping timer running, no 'close' event,
980
+ // peer's socket never destroyed). RFC 6455 §7.1.1 treats a TCP
981
+ // close without a prior Close frame as abnormal closure: surface
982
+ // the lifecycle event and end our writable side so the socket
983
+ // actually tears down. _transitionToClosed is idempotent, so the
984
+ // native 'close' that follows is a no-op.
985
+ if (self._state !== STATE_CLOSED) {
986
+ self._transitionToClosed(1006, "abnormal closure", false, null);
987
+ }
988
+ try { socket.end(); } catch (_e) { /* socket already closing */ }
989
+ });
964
990
  }
965
991
 
966
992
  // Single state-transition method. Idempotent — repeat calls after
@@ -1541,6 +1567,10 @@ module.exports = {
1541
1567
  // Server-side entrypoints
1542
1568
  handleUpgrade: handleUpgrade, // h1 — RFC 6455 HTTP upgrade
1543
1569
  handleExtendedConnect: handleExtendedConnect, // h2 — RFC 8441 Extended CONNECT
1570
+ // Internal helper exposed for tests — the Sec-WebSocket-Extensions
1571
+ // parser (RFC 7692 negotiation feeds off this). Underscore-prefixed so
1572
+ // it is not part of the public primitive surface.
1573
+ _parseExtensionHeader: _parseExtensionHeader,
1544
1574
  // Constants
1545
1575
  GUID: GUID,
1546
1576
  REFUSED_AUTH_QUERY_PARAMS: REFUSED_AUTH_QUERY_PARAMS,
@@ -287,6 +287,11 @@ function create(scriptPath, opts) {
287
287
  reason: "workerpool/worker-error",
288
288
  message: (err && err.message) || String(err),
289
289
  });
290
+ // Mark the slot dying BEFORE _finishTask. _finishTask sets slot.busy =
291
+ // false and drains the queue, so an unmarked slot would be handed a
292
+ // freshly-queued task that then dies with this same worker. _recycleWorker
293
+ // re-asserts the flag idempotently.
294
+ slot.recycling = true;
290
295
  if (failingTask) {
291
296
  _finishTask(slot, true,
292
297
  new WorkerPoolError("workerpool/worker-error",
@@ -331,6 +336,12 @@ function create(scriptPath, opts) {
331
336
  workerId: slot.id, taskId: taskId, taskTimeoutMs: taskTimeoutMs,
332
337
  });
333
338
  var failingTask = slot.currentTask;
339
+ // Mark the slot dying BEFORE _finishTask drains the queue, so the drain
340
+ // skips this about-to-be-terminated slot instead of dispatching a queued
341
+ // task onto it (which would die with the worker on terminate, surfacing as
342
+ // workerpool/worker-exit on a task that never ran). _recycleWorker
343
+ // re-asserts the flag idempotently.
344
+ slot.recycling = true;
334
345
  if (failingTask) {
335
346
  _finishTask(slot, true,
336
347
  new WorkerPoolError("workerpool/timeout",