@blamejs/blamejs-shop 0.4.56 → 0.4.58

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 (402) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/affiliates.js +35 -4
  3. package/lib/api-keys.js +17 -2
  4. package/lib/asset-manifest.json +1 -1
  5. package/lib/backorder.js +21 -4
  6. package/lib/click-and-collect.js +11 -2
  7. package/lib/credit-limits.js +132 -84
  8. package/lib/vendor/MANIFEST.json +426 -366
  9. package/lib/vendor/blamejs/.github/codeql/codeql-config.yml +25 -0
  10. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  11. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +1 -1
  12. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +1 -1
  13. package/lib/vendor/blamejs/.github/workflows/ci.yml +13 -13
  14. package/lib/vendor/blamejs/.github/workflows/codeql.yml +8 -7
  15. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +2 -2
  16. package/lib/vendor/blamejs/.github/workflows/release-container.yml +4 -4
  17. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +1 -1
  18. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  19. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  20. package/lib/vendor/blamejs/api-snapshot.json +1381 -4
  21. package/lib/vendor/blamejs/eslint.config.mjs +1 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +4 -1
  23. package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +5 -2
  24. package/lib/vendor/blamejs/examples/wiki/routes/pages.js +4 -1
  25. package/lib/vendor/blamejs/fuzz/guard-text.fuzz.js +20 -0
  26. package/lib/vendor/blamejs/index.js +2 -0
  27. package/lib/vendor/blamejs/lib/a2a-tasks.js +7 -23
  28. package/lib/vendor/blamejs/lib/acme.js +6 -5
  29. package/lib/vendor/blamejs/lib/agent-event-bus.js +5 -4
  30. package/lib/vendor/blamejs/lib/agent-idempotency.js +2 -5
  31. package/lib/vendor/blamejs/lib/agent-orchestrator.js +2 -5
  32. package/lib/vendor/blamejs/lib/agent-saga.js +3 -5
  33. package/lib/vendor/blamejs/lib/agent-tenant.js +2 -5
  34. package/lib/vendor/blamejs/lib/ai-adverse-decision.js +2 -15
  35. package/lib/vendor/blamejs/lib/ai-capability.js +1 -6
  36. package/lib/vendor/blamejs/lib/ai-dp.js +1 -5
  37. package/lib/vendor/blamejs/lib/ai-input.js +2 -2
  38. package/lib/vendor/blamejs/lib/ai-pref.js +3 -8
  39. package/lib/vendor/blamejs/lib/ai-quota.js +3 -14
  40. package/lib/vendor/blamejs/lib/api-key.js +37 -28
  41. package/lib/vendor/blamejs/lib/archive-adapters.js +2 -4
  42. package/lib/vendor/blamejs/lib/archive-entry-policy.js +32 -0
  43. package/lib/vendor/blamejs/lib/archive-read.js +5 -17
  44. package/lib/vendor/blamejs/lib/archive-tar-read.js +5 -16
  45. package/lib/vendor/blamejs/lib/archive.js +2 -10
  46. package/lib/vendor/blamejs/lib/arg-parser.js +7 -6
  47. package/lib/vendor/blamejs/lib/asyncapi-traits.js +2 -6
  48. package/lib/vendor/blamejs/lib/atomic-file.js +108 -31
  49. package/lib/vendor/blamejs/lib/audit-chain.js +133 -53
  50. package/lib/vendor/blamejs/lib/audit-daily-review.js +24 -14
  51. package/lib/vendor/blamejs/lib/audit-emit.js +82 -0
  52. package/lib/vendor/blamejs/lib/audit-sign.js +257 -0
  53. package/lib/vendor/blamejs/lib/audit.js +84 -0
  54. package/lib/vendor/blamejs/lib/auth/access-lock.js +5 -27
  55. package/lib/vendor/blamejs/lib/auth/dpop.js +23 -35
  56. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +9 -15
  57. package/lib/vendor/blamejs/lib/auth/jwt-external.js +26 -8
  58. package/lib/vendor/blamejs/lib/auth/jwt.js +13 -15
  59. package/lib/vendor/blamejs/lib/auth/lockout.js +6 -25
  60. package/lib/vendor/blamejs/lib/auth/oauth.js +67 -45
  61. package/lib/vendor/blamejs/lib/auth/oid4vci.js +55 -32
  62. package/lib/vendor/blamejs/lib/auth/oid4vp.js +3 -2
  63. package/lib/vendor/blamejs/lib/auth/openid-federation.js +6 -6
  64. package/lib/vendor/blamejs/lib/auth/passkey.js +3 -3
  65. package/lib/vendor/blamejs/lib/auth/password.js +7 -1
  66. package/lib/vendor/blamejs/lib/auth/saml.js +37 -27
  67. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +2 -14
  68. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +2 -14
  69. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +1 -1
  70. package/lib/vendor/blamejs/lib/auth/status-list.js +7 -7
  71. package/lib/vendor/blamejs/lib/auth/step-up.js +6 -12
  72. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +6 -37
  73. package/lib/vendor/blamejs/lib/backup/bundle.js +11 -18
  74. package/lib/vendor/blamejs/lib/backup/index.js +14 -47
  75. package/lib/vendor/blamejs/lib/bounded-map.js +112 -1
  76. package/lib/vendor/blamejs/lib/breach-deadline.js +1 -11
  77. package/lib/vendor/blamejs/lib/cache.js +7 -18
  78. package/lib/vendor/blamejs/lib/cbor.js +2 -1
  79. package/lib/vendor/blamejs/lib/cdn-cache-control.js +8 -9
  80. package/lib/vendor/blamejs/lib/cert.js +3 -10
  81. package/lib/vendor/blamejs/lib/chain-writer.js +162 -47
  82. package/lib/vendor/blamejs/lib/cli.js +5 -1
  83. package/lib/vendor/blamejs/lib/client-hints.js +7 -9
  84. package/lib/vendor/blamejs/lib/cloud-events.js +40 -31
  85. package/lib/vendor/blamejs/lib/cluster-storage.js +2 -38
  86. package/lib/vendor/blamejs/lib/cms-codec.js +2 -1
  87. package/lib/vendor/blamejs/lib/codepoint-class.js +67 -1
  88. package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +1 -6
  89. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +2 -4
  90. package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -11
  91. package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +21 -28
  92. package/lib/vendor/blamejs/lib/compliance-sanctions.js +2 -14
  93. package/lib/vendor/blamejs/lib/compliance.js +2 -9
  94. package/lib/vendor/blamejs/lib/config-drift.js +2 -12
  95. package/lib/vendor/blamejs/lib/content-digest.js +10 -8
  96. package/lib/vendor/blamejs/lib/cookies.js +5 -11
  97. package/lib/vendor/blamejs/lib/cose.js +19 -11
  98. package/lib/vendor/blamejs/lib/cra-report.js +1 -11
  99. package/lib/vendor/blamejs/lib/crypto-field.js +5 -10
  100. package/lib/vendor/blamejs/lib/crypto.js +120 -3
  101. package/lib/vendor/blamejs/lib/csp.js +235 -3
  102. package/lib/vendor/blamejs/lib/daemon.js +42 -41
  103. package/lib/vendor/blamejs/lib/data-act.js +19 -9
  104. package/lib/vendor/blamejs/lib/db-query.js +6 -40
  105. package/lib/vendor/blamejs/lib/db.js +34 -12
  106. package/lib/vendor/blamejs/lib/dbsc.js +5 -6
  107. package/lib/vendor/blamejs/lib/ddl-change-control.js +18 -14
  108. package/lib/vendor/blamejs/lib/deprecate.js +4 -5
  109. package/lib/vendor/blamejs/lib/did.js +6 -2
  110. package/lib/vendor/blamejs/lib/dsr.js +8 -12
  111. package/lib/vendor/blamejs/lib/external-db-migrate.js +21 -22
  112. package/lib/vendor/blamejs/lib/external-db.js +14 -26
  113. package/lib/vendor/blamejs/lib/fda-21cfr11.js +12 -8
  114. package/lib/vendor/blamejs/lib/fdx.js +22 -18
  115. package/lib/vendor/blamejs/lib/file-upload.js +80 -66
  116. package/lib/vendor/blamejs/lib/flag-evaluation-context.js +5 -8
  117. package/lib/vendor/blamejs/lib/framework-error.js +12 -0
  118. package/lib/vendor/blamejs/lib/framework-schema.js +19 -0
  119. package/lib/vendor/blamejs/lib/fsm.js +7 -12
  120. package/lib/vendor/blamejs/lib/gate-contract.js +869 -38
  121. package/lib/vendor/blamejs/lib/gdpr-ropa.js +4 -13
  122. package/lib/vendor/blamejs/lib/graphql-federation.js +1 -1
  123. package/lib/vendor/blamejs/lib/guard-agent-registry.js +2 -1
  124. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  125. package/lib/vendor/blamejs/lib/guard-archive.js +9 -30
  126. package/lib/vendor/blamejs/lib/guard-auth.js +23 -80
  127. package/lib/vendor/blamejs/lib/guard-cidr.js +20 -96
  128. package/lib/vendor/blamejs/lib/guard-csv.js +135 -196
  129. package/lib/vendor/blamejs/lib/guard-domain.js +23 -106
  130. package/lib/vendor/blamejs/lib/guard-dsn.js +16 -13
  131. package/lib/vendor/blamejs/lib/guard-email.js +46 -53
  132. package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
  133. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +2 -1
  134. package/lib/vendor/blamejs/lib/guard-filename.js +12 -60
  135. package/lib/vendor/blamejs/lib/guard-graphql.js +28 -75
  136. package/lib/vendor/blamejs/lib/guard-html-wcag.js +15 -2
  137. package/lib/vendor/blamejs/lib/guard-html.js +65 -117
  138. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +2 -1
  139. package/lib/vendor/blamejs/lib/guard-image.js +280 -77
  140. package/lib/vendor/blamejs/lib/guard-imap-command.js +8 -9
  141. package/lib/vendor/blamejs/lib/guard-json.js +87 -103
  142. package/lib/vendor/blamejs/lib/guard-jsonpath.js +20 -88
  143. package/lib/vendor/blamejs/lib/guard-jwt.js +32 -114
  144. package/lib/vendor/blamejs/lib/guard-list-id.js +2 -7
  145. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -7
  146. package/lib/vendor/blamejs/lib/guard-mail-compose.js +5 -6
  147. package/lib/vendor/blamejs/lib/guard-mail-move.js +2 -1
  148. package/lib/vendor/blamejs/lib/guard-mail-query.js +5 -3
  149. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +6 -7
  150. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +5 -4
  151. package/lib/vendor/blamejs/lib/guard-markdown.js +76 -110
  152. package/lib/vendor/blamejs/lib/guard-message-id.js +5 -6
  153. package/lib/vendor/blamejs/lib/guard-mime.js +20 -99
  154. package/lib/vendor/blamejs/lib/guard-oauth.js +19 -73
  155. package/lib/vendor/blamejs/lib/guard-pdf.js +65 -72
  156. package/lib/vendor/blamejs/lib/guard-pop3-command.js +12 -13
  157. package/lib/vendor/blamejs/lib/guard-posture-chain.js +2 -1
  158. package/lib/vendor/blamejs/lib/guard-regex.js +24 -99
  159. package/lib/vendor/blamejs/lib/guard-saga-config.js +2 -1
  160. package/lib/vendor/blamejs/lib/guard-shell.js +22 -87
  161. package/lib/vendor/blamejs/lib/guard-smtp-command.js +8 -11
  162. package/lib/vendor/blamejs/lib/guard-sql.js +15 -13
  163. package/lib/vendor/blamejs/lib/guard-stream-args.js +2 -1
  164. package/lib/vendor/blamejs/lib/guard-svg.js +95 -140
  165. package/lib/vendor/blamejs/lib/guard-template.js +23 -80
  166. package/lib/vendor/blamejs/lib/guard-tenant-id.js +2 -1
  167. package/lib/vendor/blamejs/lib/guard-text.js +592 -0
  168. package/lib/vendor/blamejs/lib/guard-time.js +27 -95
  169. package/lib/vendor/blamejs/lib/guard-uuid.js +21 -93
  170. package/lib/vendor/blamejs/lib/guard-xml.js +76 -106
  171. package/lib/vendor/blamejs/lib/guard-yaml.js +24 -60
  172. package/lib/vendor/blamejs/lib/http-client-cache.js +5 -12
  173. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +2 -4
  174. package/lib/vendor/blamejs/lib/http-client.js +8 -21
  175. package/lib/vendor/blamejs/lib/http-message-signature.js +3 -2
  176. package/lib/vendor/blamejs/lib/i18n-messageformat.js +5 -7
  177. package/lib/vendor/blamejs/lib/i18n.js +83 -26
  178. package/lib/vendor/blamejs/lib/inbox.js +8 -8
  179. package/lib/vendor/blamejs/lib/incident-report.js +3 -21
  180. package/lib/vendor/blamejs/lib/ip-utils.js +49 -6
  181. package/lib/vendor/blamejs/lib/jobs.js +3 -2
  182. package/lib/vendor/blamejs/lib/keychain.js +6 -18
  183. package/lib/vendor/blamejs/lib/legal-hold.js +6 -15
  184. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +44 -112
  185. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +17 -14
  186. package/lib/vendor/blamejs/lib/log-stream-otlp.js +16 -80
  187. package/lib/vendor/blamejs/lib/log-stream-webhook.js +20 -92
  188. package/lib/vendor/blamejs/lib/mail-arc-sign.js +8 -3
  189. package/lib/vendor/blamejs/lib/mail-arf.js +3 -2
  190. package/lib/vendor/blamejs/lib/mail-auth.js +40 -66
  191. package/lib/vendor/blamejs/lib/mail-bimi.js +19 -39
  192. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +3 -2
  193. package/lib/vendor/blamejs/lib/mail-dav.js +8 -35
  194. package/lib/vendor/blamejs/lib/mail-deploy.js +6 -9
  195. package/lib/vendor/blamejs/lib/mail-dkim.js +19 -38
  196. package/lib/vendor/blamejs/lib/mail-greylist.js +15 -26
  197. package/lib/vendor/blamejs/lib/mail-helo.js +2 -3
  198. package/lib/vendor/blamejs/lib/mail-journal.js +2 -1
  199. package/lib/vendor/blamejs/lib/mail-mdn.js +4 -3
  200. package/lib/vendor/blamejs/lib/mail-rbl.js +5 -8
  201. package/lib/vendor/blamejs/lib/mail-scan.js +2 -2
  202. package/lib/vendor/blamejs/lib/mail-send-deliver.js +33 -20
  203. package/lib/vendor/blamejs/lib/mail-server-imap.js +32 -87
  204. package/lib/vendor/blamejs/lib/mail-server-jmap.js +35 -51
  205. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +29 -83
  206. package/lib/vendor/blamejs/lib/mail-server-mx.js +33 -74
  207. package/lib/vendor/blamejs/lib/mail-server-net.js +177 -0
  208. package/lib/vendor/blamejs/lib/mail-server-pop3.js +30 -83
  209. package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +30 -6
  210. package/lib/vendor/blamejs/lib/mail-server-submission.js +34 -73
  211. package/lib/vendor/blamejs/lib/mail-server-tls.js +89 -0
  212. package/lib/vendor/blamejs/lib/mail-spam-score.js +7 -8
  213. package/lib/vendor/blamejs/lib/mail-store.js +3 -2
  214. package/lib/vendor/blamejs/lib/mail.js +6 -11
  215. package/lib/vendor/blamejs/lib/markup-escape.js +31 -0
  216. package/lib/vendor/blamejs/lib/markup-tokenizer.js +54 -0
  217. package/lib/vendor/blamejs/lib/mcp-tool-registry.js +26 -23
  218. package/lib/vendor/blamejs/lib/mcp.js +1 -1
  219. package/lib/vendor/blamejs/lib/mdoc.js +11 -12
  220. package/lib/vendor/blamejs/lib/metrics.js +32 -30
  221. package/lib/vendor/blamejs/lib/middleware/age-gate.js +3 -23
  222. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +11 -22
  223. package/lib/vendor/blamejs/lib/middleware/assetlinks.js +2 -7
  224. package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +2 -1
  225. package/lib/vendor/blamejs/lib/middleware/body-parser.js +31 -48
  226. package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +7 -10
  227. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +2 -10
  228. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +13 -2
  229. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -26
  230. package/lib/vendor/blamejs/lib/middleware/deny-response.js +19 -1
  231. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +7 -0
  232. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +4 -20
  233. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +20 -28
  234. package/lib/vendor/blamejs/lib/middleware/scim-server.js +3 -2
  235. package/lib/vendor/blamejs/lib/middleware/security-headers.js +9 -1
  236. package/lib/vendor/blamejs/lib/middleware/security-txt.js +2 -6
  237. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +12 -27
  238. package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +2 -7
  239. package/lib/vendor/blamejs/lib/migrations.js +4 -13
  240. package/lib/vendor/blamejs/lib/mime-parse.js +34 -17
  241. package/lib/vendor/blamejs/lib/module-loader.js +44 -0
  242. package/lib/vendor/blamejs/lib/money.js +105 -0
  243. package/lib/vendor/blamejs/lib/mtls-ca.js +116 -36
  244. package/lib/vendor/blamejs/lib/network-byte-quota.js +4 -18
  245. package/lib/vendor/blamejs/lib/network-dane.js +8 -6
  246. package/lib/vendor/blamejs/lib/network-dns-resolver.js +97 -6
  247. package/lib/vendor/blamejs/lib/network-dnssec.js +16 -16
  248. package/lib/vendor/blamejs/lib/network-heartbeat.js +3 -2
  249. package/lib/vendor/blamejs/lib/network-smtp-policy.js +29 -41
  250. package/lib/vendor/blamejs/lib/network-tls.js +40 -42
  251. package/lib/vendor/blamejs/lib/nis2-report.js +1 -11
  252. package/lib/vendor/blamejs/lib/nonce-store.js +81 -3
  253. package/lib/vendor/blamejs/lib/numeric-bounds.js +22 -8
  254. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +2 -6
  255. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +5 -45
  256. package/lib/vendor/blamejs/lib/object-store/gcs.js +8 -71
  257. package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -5
  258. package/lib/vendor/blamejs/lib/object-store/http-request.js +128 -0
  259. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +2 -1
  260. package/lib/vendor/blamejs/lib/object-store/sigv4.js +9 -77
  261. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -25
  262. package/lib/vendor/blamejs/lib/observability.js +95 -0
  263. package/lib/vendor/blamejs/lib/openapi-paths-builder.js +7 -3
  264. package/lib/vendor/blamejs/lib/otel-export.js +7 -10
  265. package/lib/vendor/blamejs/lib/outbox.js +43 -37
  266. package/lib/vendor/blamejs/lib/pagination.js +11 -15
  267. package/lib/vendor/blamejs/lib/parsers/safe-env.js +5 -4
  268. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +10 -4
  269. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +11 -9
  270. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +2 -2
  271. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +7 -6
  272. package/lib/vendor/blamejs/lib/pick.js +63 -5
  273. package/lib/vendor/blamejs/lib/pipl-cn.js +69 -59
  274. package/lib/vendor/blamejs/lib/privacy-pass.js +8 -6
  275. package/lib/vendor/blamejs/lib/problem-details.js +2 -5
  276. package/lib/vendor/blamejs/lib/pubsub.js +4 -8
  277. package/lib/vendor/blamejs/lib/redact.js +2 -1
  278. package/lib/vendor/blamejs/lib/render.js +4 -2
  279. package/lib/vendor/blamejs/lib/request-helpers.js +133 -6
  280. package/lib/vendor/blamejs/lib/restore.js +5 -22
  281. package/lib/vendor/blamejs/lib/retention.js +3 -5
  282. package/lib/vendor/blamejs/lib/safe-async.js +457 -0
  283. package/lib/vendor/blamejs/lib/safe-buffer.js +137 -6
  284. package/lib/vendor/blamejs/lib/safe-decompress.js +2 -1
  285. package/lib/vendor/blamejs/lib/safe-dns.js +2 -1
  286. package/lib/vendor/blamejs/lib/safe-ical.js +12 -26
  287. package/lib/vendor/blamejs/lib/safe-json.js +7 -8
  288. package/lib/vendor/blamejs/lib/safe-jsonpath.js +6 -5
  289. package/lib/vendor/blamejs/lib/safe-mime.js +25 -29
  290. package/lib/vendor/blamejs/lib/safe-redirect.js +2 -5
  291. package/lib/vendor/blamejs/lib/safe-schema.js +7 -6
  292. package/lib/vendor/blamejs/lib/safe-sql.js +126 -0
  293. package/lib/vendor/blamejs/lib/safe-vcard.js +12 -26
  294. package/lib/vendor/blamejs/lib/sandbox-worker.js +9 -2
  295. package/lib/vendor/blamejs/lib/sandbox.js +3 -2
  296. package/lib/vendor/blamejs/lib/scheduler.js +5 -12
  297. package/lib/vendor/blamejs/lib/sec-cyber.js +82 -37
  298. package/lib/vendor/blamejs/lib/seeders.js +4 -11
  299. package/lib/vendor/blamejs/lib/self-update.js +92 -69
  300. package/lib/vendor/blamejs/lib/session-device-binding.js +112 -66
  301. package/lib/vendor/blamejs/lib/session.js +194 -6
  302. package/lib/vendor/blamejs/lib/sql.js +225 -78
  303. package/lib/vendor/blamejs/lib/sse.js +6 -10
  304. package/lib/vendor/blamejs/lib/static.js +136 -98
  305. package/lib/vendor/blamejs/lib/storage.js +4 -2
  306. package/lib/vendor/blamejs/lib/structured-fields.js +275 -16
  307. package/lib/vendor/blamejs/lib/tenant-quota.js +2 -20
  308. package/lib/vendor/blamejs/lib/tsa.js +11 -15
  309. package/lib/vendor/blamejs/lib/validate-opts.js +154 -8
  310. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +30 -48
  311. package/lib/vendor/blamejs/lib/vault-aad.js +3 -2
  312. package/lib/vendor/blamejs/lib/vc.js +2 -7
  313. package/lib/vendor/blamejs/lib/vex.js +35 -13
  314. package/lib/vendor/blamejs/lib/web-push-vapid.js +23 -20
  315. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +706 -0
  316. package/lib/vendor/blamejs/lib/webhook.js +43 -18
  317. package/lib/vendor/blamejs/lib/websocket-channels.js +9 -7
  318. package/lib/vendor/blamejs/lib/websocket.js +7 -3
  319. package/lib/vendor/blamejs/lib/worm.js +2 -3
  320. package/lib/vendor/blamejs/lib/ws-client.js +8 -10
  321. package/lib/vendor/blamejs/package.json +1 -1
  322. package/lib/vendor/blamejs/release-notes/v0.15.13.json +81 -0
  323. package/lib/vendor/blamejs/scripts/check-changelog-extract.js +1 -1
  324. package/lib/vendor/blamejs/test/00-primitives.js +136 -7
  325. package/lib/vendor/blamejs/test/10-state.js +9 -3
  326. package/lib/vendor/blamejs/test/30-chain.js +40 -0
  327. package/lib/vendor/blamejs/test/helpers/check.js +18 -0
  328. package/lib/vendor/blamejs/test/helpers/db.js +4 -0
  329. package/lib/vendor/blamejs/test/helpers/index.js +1 -0
  330. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +2 -1
  331. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +2 -1
  332. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +8 -1
  333. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +1 -1
  334. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +2 -1
  335. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +269 -0
  336. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +149 -0
  337. package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +51 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +88 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +55 -1
  340. package/lib/vendor/blamejs/test/layer-0-primitives/backup-object-store-adapter.test.js +2 -2
  341. package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +1 -1
  342. package/lib/vendor/blamejs/test/layer-0-primitives/bounded-map.test.js +129 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/chain-writer-multichain.test.js +107 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +12 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +2788 -3214
  346. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +78 -0
  347. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +63 -0
  348. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +2 -1
  349. package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +50 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +1 -1
  351. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +2 -1
  352. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-resolve-opts.test.js +76 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +9 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract-content-gate.test.js +290 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +84 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +78 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +23 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-gate-disposition-coverage.test.js +93 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +60 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +184 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +54 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +10 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +45 -0
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +101 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +18 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +76 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/guard-text.test.js +365 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +35 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +36 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +20 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +83 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +10 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +39 -0
  376. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +36 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +17 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +39 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +17 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/mime-parse.test.js +106 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +17 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-revocation.test.js +98 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-release.test.js +77 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +48 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-memory-getorinsert.test.js +100 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +88 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +278 -0
  388. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +37 -0
  389. package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +14 -0
  390. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +19 -0
  391. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +1 -1
  392. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +2 -1
  393. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +18 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +1 -1
  395. package/lib/vendor/blamejs/test/layer-0-primitives/session-valid-from.test.js +73 -0
  396. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +100 -0
  397. package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +80 -0
  398. package/lib/vendor/blamejs/test/layer-0-primitives/validate-opts-shape.test.js +235 -0
  399. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +374 -0
  400. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +75 -8
  401. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +3 -3
  402. package/package.json +1 -1
@@ -14,7 +14,9 @@ var C = require("./constants");
14
14
  var lazyRequire = require("./lazy-require");
15
15
  var safeBuffer = require("./safe-buffer");
16
16
  var archiveTar = require("./archive-tar");
17
+ var archiveEntryPolicy = require("./archive-entry-policy");
17
18
  var atomicFile = require("./atomic-file");
19
+ var auditEmit = require("./audit-emit");
18
20
 
19
21
  var TarError = archiveTar.TarError;
20
22
  var _parseHeader = archiveTar._parseHeader;
@@ -45,29 +47,16 @@ var DEFAULT_BOMB_POLICY = Object.freeze({
45
47
  maxExpansionRatio: 100, // tar has no compression-ratio concept, but keep field for orchestrator policy parity
46
48
  });
47
49
 
48
- var DEFAULT_ENTRY_TYPE_POLICY = Object.freeze({
49
- symlinks: false,
50
- hardlinks: false,
51
- devices: false,
52
- fifos: false,
53
- sockets: false,
54
- });
50
+ var DEFAULT_ENTRY_TYPE_POLICY = archiveEntryPolicy.DEFAULT_ENTRY_TYPE_POLICY;
55
51
 
56
52
  function _normalizeBombPolicy(p) {
57
53
  if (!p) return DEFAULT_BOMB_POLICY;
58
54
  return Object.freeze(Object.assign({}, DEFAULT_BOMB_POLICY, p));
59
55
  }
60
56
 
61
- function _normalizeEntryTypePolicy(p) {
62
- if (!p) return DEFAULT_ENTRY_TYPE_POLICY;
63
- return Object.freeze(Object.assign({}, DEFAULT_ENTRY_TYPE_POLICY, p));
64
- }
57
+ var _normalizeEntryTypePolicy = archiveEntryPolicy.normalize;
65
58
 
66
- function _emitAudit(opts, action, outcome, metadata) {
67
- if (!opts || !opts.audit || typeof opts.audit.safeEmit !== "function") return;
68
- try { opts.audit.safeEmit({ action: action, outcome: outcome, metadata: metadata }); }
69
- catch (_e) { /* drop-silent */ }
70
- }
59
+ var _emitAudit = auditEmit.emitToSink; // operator-sink audit emit (opts.audit)
71
60
 
72
61
  function _isZeroBlock(buf) {
73
62
  for (var i = 0; i < BLOCK_SIZE; i += 1) {
@@ -58,6 +58,7 @@ var nodeStream = require("node:stream");
58
58
  var streamPromises = require("node:stream/promises");
59
59
  var C = require("./constants");
60
60
  var { defineClass } = require("./framework-error");
61
+ var auditEmit = require("./audit-emit");
61
62
 
62
63
  var ArchiveError = defineClass("ArchiveError", { alwaysPermanent: true });
63
64
 
@@ -481,16 +482,7 @@ function zip() {
481
482
  return buf.length;
482
483
  }
483
484
 
484
- function _emitAudit(opts, action, outcome, metadata) {
485
- if (!opts || !opts.audit || typeof opts.audit.safeEmit !== "function") return;
486
- try {
487
- opts.audit.safeEmit({
488
- action: action,
489
- outcome: outcome,
490
- metadata: metadata,
491
- });
492
- } catch (_e) { /* drop-silent — audit sinks must never crash the producer */ }
493
- }
485
+ var _emitAudit = auditEmit.emitToSink; // operator-sink audit emit (opts.audit)
494
486
 
495
487
  function _writeChunk(writable, chunk) {
496
488
  return new Promise(function (resolve, reject) {
@@ -36,6 +36,7 @@
36
36
  */
37
37
 
38
38
  var { defineClass } = require("./framework-error");
39
+ var pick = require("./pick");
39
40
 
40
41
  var ArgParserError = defineClass("ArgParserError", { alwaysPermanent: true });
41
42
 
@@ -44,8 +45,8 @@ var SUPPORTED_TYPES = ["string", "number", "boolean", "list"];
44
45
  // Names operators can never use for a flag. Prototype-pollution defense:
45
46
  // even though the parser internally uses Object.create(null), downstream
46
47
  // callers spreading parsed.flags into a normal object would otherwise
47
- // overwrite the prototype.
48
- var FORBIDDEN_NAMES = ["__proto__", "constructor", "prototype"];
48
+ // overwrite the prototype. The forbidden-name set is the framework's one
49
+ // prototype-pollution key guard pick.isPoisonedKey.
49
50
 
50
51
  function _isPlainNonEmpty(s) {
51
52
  return typeof s === "string" && s.length > 0;
@@ -56,7 +57,7 @@ function _validateFlagName(name) {
56
57
  throw new ArgParserError("arg-parser/flag-name-invalid",
57
58
  "flag name must be a non-empty string");
58
59
  }
59
- if (FORBIDDEN_NAMES.indexOf(name) !== -1) {
60
+ if (pick.isPoisonedKey(name)) {
60
61
  throw new ArgParserError("arg-parser/flag-name-forbidden",
61
62
  "flag name '" + name + "' is reserved");
62
63
  }
@@ -298,7 +299,7 @@ function _consumeFlags(index, tokens) {
298
299
 
299
300
  if (tok.indexOf("--") === 0) {
300
301
  var rest = tok.slice(2);
301
- if (FORBIDDEN_NAMES.indexOf(rest.split("=")[0]) !== -1) {
302
+ if (pick.isPoisonedKey(rest.split("=")[0])) {
302
303
  throw new ArgParserError("arg-parser/argv-forbidden-name",
303
304
  "flag '--" + rest.split("=")[0] + "' is reserved");
304
305
  }
@@ -672,14 +673,14 @@ function parseRaw(argv) {
672
673
  } else {
673
674
  val = true;
674
675
  }
675
- if (FORBIDDEN_NAMES.indexOf(name) !== -1) {
676
+ if (pick.isPoisonedKey(name)) {
676
677
  throw new ArgParserError("arg-parser/argv-forbidden-name",
677
678
  "flag '--" + name + "' is reserved");
678
679
  }
679
680
  flags[name] = val;
680
681
  } else if (tok.indexOf("-") === 0 && tok.length === 2) {
681
682
  var s = tok.slice(1);
682
- if (FORBIDDEN_NAMES.indexOf(s) !== -1) {
683
+ if (pick.isPoisonedKey(s)) {
683
684
  throw new ArgParserError("arg-parser/argv-forbidden-name",
684
685
  "flag '-" + s + "' is reserved");
685
686
  }
@@ -109,12 +109,8 @@ function _mergeKey(key, base, overlay) {
109
109
  if (typeof base === "object" && typeof overlay === "object" &&
110
110
  !Array.isArray(base) && !Array.isArray(overlay)) {
111
111
  var out = {};
112
- for (var k1 in base) {
113
- if (Object.prototype.hasOwnProperty.call(base, k1)) out[k1] = base[k1];
114
- }
115
- for (var k2 in overlay) {
116
- if (Object.prototype.hasOwnProperty.call(overlay, k2)) out[k2] = overlay[k2];
117
- }
112
+ validateOpts.assignOwnEnumerable(out, base);
113
+ validateOpts.assignOwnEnumerable(out, overlay);
118
114
  return out;
119
115
  }
120
116
  return overlay; // scalar overrides
@@ -703,39 +703,88 @@ function _validateMaxBytes(maxBytes) {
703
703
  }
704
704
  }
705
705
 
706
- function _readSyncCore(filepath, opts) {
707
- _validateMaxBytes(opts.maxBytes);
708
- // CodeQL js/file-system-race defense — TOCTOU-safe-read scaffold.
709
- // Open the fd first, then fstat the same fd (so size + content
710
- // measurement bind to the inode the fd holds open). An attacker
711
- // can't swap the file between size-check and read because the fd
712
- // is anchored to the original inode. ENOENT surfaces from open()
713
- // rather than the previous existsSync() pre-check.
714
- //
715
- // The third argument pins an owner-only mode (0o600). The flag is
716
- // read-only ("r" O_RDONLY, no O_CREAT) so the mode is inert on
717
- // disk, but specifying it keeps this open out of the insecure-temp-
718
- // file class (CWE-377): the read can never create a world/group-
719
- // accessible file even when `filepath` is rooted under a temp dir.
706
+ /**
707
+ * @primitive b.atomicFile.fdSafeReadSync
708
+ * @signature b.atomicFile.fdSafeReadSync(filepath, opts?)
709
+ * @since 0.15.13
710
+ * @status stable
711
+ * @related b.atomicFile.readSync, b.atomicFile.read
712
+ *
713
+ * TOCTOU-safe synchronous file read (CWE-367 / js/file-system-race). Opens
714
+ * the path read-only, then binds every subsequent measurement — size,
715
+ * content, integrity to the inode the fd holds open, so an attacker who
716
+ * swaps the file between stat and read can't change which bytes come back.
717
+ * The optional guards layer on top of that core: a byte cap (`maxBytes`),
718
+ * symlink refusal + inode-equality (`refuseSymlink` / `inodeCheck` the
719
+ * strongest defense, for operator-writable source paths), an integrity
720
+ * hash (`expectedHash`, SHA3-512), and a short-read policy (throw, or
721
+ * slice when `allowShortRead`). Each caller maps a failure KIND to its own
722
+ * typed error via `errorFor`, so the message / code / audit posture stays
723
+ * per-domain; the default raises an `AtomicFileError`.
724
+ *
725
+ * @opts
726
+ * mode: number, // open mode (default 0o600; inert under O_RDONLY)
727
+ * maxBytes: number, // refuse a file larger than this (default: no cap)
728
+ * refuseSymlink: boolean, // lstat + refuse a symlink source (default: false)
729
+ * inodeCheck: boolean, // refuse if the fd inode != the lstat inode (needs refuseSymlink)
730
+ * expectedHash: string, // SHA3-512 the content must match (default: none)
731
+ * encoding: string, // decode to a string (default: return a Buffer)
732
+ * allowShortRead: boolean, // slice to the bytes read instead of throwing (default: false)
733
+ * errorFor: Function, // (kind, detail) => Error|undefined; kinds: enoent / symlink / too-large / toctou / short-read / integrity
734
+ *
735
+ * @example
736
+ * var cfg = b.atomicFile.fdSafeReadSync("/etc/app/config.json", {
737
+ * maxBytes: b.constants.BYTES.mib(1),
738
+ * encoding: "utf8",
739
+ * });
740
+ */
741
+ function fdSafeReadSync(filepath, opts) {
742
+ opts = opts || {};
743
+ var errorFor = opts.errorFor || function (kind, detail) {
744
+ return new AtomicFileError((detail && detail.message) || ("atomic-file: " + kind), "atomic-file/" + kind);
745
+ };
746
+ if (opts.maxBytes !== undefined) _validateMaxBytes(opts.maxBytes);
747
+ var mode = opts.mode === undefined ? 0o600 : opts.mode;
748
+ // refuseSymlink: lstat the path first and refuse a symlink source —
749
+ // the strongest TOCTOU posture (open() would follow the link). The
750
+ // fd's inode is re-checked against this lstat's inode below.
751
+ var lstat = null;
752
+ if (opts.refuseSymlink) {
753
+ lstat = nodeFs.lstatSync(filepath);
754
+ if (lstat.isSymbolicLink()) throw errorFor("symlink", { path: filepath });
755
+ if (opts.maxBytes !== undefined && lstat.size > opts.maxBytes) {
756
+ throw errorFor("too-large", { size: lstat.size, max: opts.maxBytes });
757
+ }
758
+ }
759
+ // The third argument pins an owner-only mode (0o600 default). The flag
760
+ // is read-only ("r" → O_RDONLY, no O_CREAT) so the mode is inert on
761
+ // disk, but specifying it keeps this open out of the insecure-temp-file
762
+ // class (CWE-377). ENOENT surfaces from open() rather than a pre-check;
763
+ // a caller's errorFor("enoent") may translate it, else it rethrows raw.
720
764
  var fd;
721
765
  try {
722
- fd = nodeFs.openSync(filepath, "r", 0o600);
766
+ fd = nodeFs.openSync(filepath, "r", mode);
723
767
  } catch (openErr) {
724
768
  if (openErr && openErr.code === "ENOENT") {
725
- var e = new AtomicFileError("file not found: " + filepath, "atomic-file/not-found");
726
- e.code = "ENOENT";
727
- throw e;
769
+ var typed = errorFor("enoent", { path: filepath, cause: openErr });
770
+ if (typed) throw typed;
728
771
  }
729
772
  throw openErr;
730
773
  }
731
774
  var buf;
732
775
  try {
733
776
  var fstat = nodeFs.fstatSync(fd);
734
- if (fstat.size > opts.maxBytes) {
735
- throw new AtomicFileError(
736
- "file size " + fstat.size + " > maxBytes " + opts.maxBytes,
737
- "atomic-file/too-large"
738
- );
777
+ // inodeCheck: the fd must point at the same inode lstat saw — any
778
+ // swap between lstat and open is a TOCTOU and is refused. A file that
779
+ // GREW past the cap between lstat and open is the same class of swap,
780
+ // so under inodeCheck a post-open over-cap is reported as toctou; a
781
+ // plain (no-inodeCheck) reader reports an over-cap as too-large.
782
+ if (lstat && opts.inodeCheck) {
783
+ if (fstat.ino !== lstat.ino || (opts.maxBytes !== undefined && fstat.size > opts.maxBytes)) {
784
+ throw errorFor("toctou", { path: filepath });
785
+ }
786
+ } else if (opts.maxBytes !== undefined && fstat.size > opts.maxBytes) {
787
+ throw errorFor("too-large", { size: fstat.size, max: opts.maxBytes });
739
788
  }
740
789
  buf = Buffer.alloc(fstat.size);
741
790
  var read = 0;
@@ -745,10 +794,8 @@ function _readSyncCore(filepath, opts) {
745
794
  read += n;
746
795
  }
747
796
  if (read !== fstat.size) {
748
- throw new AtomicFileError(
749
- "short read: " + read + " of " + fstat.size + " bytes",
750
- "atomic-file/short-read"
751
- );
797
+ if (opts.allowShortRead) { buf = buf.slice(0, read); }
798
+ else { throw errorFor("short-read", { read: read, size: fstat.size }); }
752
799
  }
753
800
  } finally {
754
801
  try { nodeFs.closeSync(fd); } catch (_c) { /* close best-effort */ }
@@ -756,15 +803,44 @@ function _readSyncCore(filepath, opts) {
756
803
  if (opts.expectedHash) {
757
804
  var actual = sha3Hash(buf);
758
805
  if (actual !== opts.expectedHash) {
759
- throw new AtomicFileError(
760
- "integrity check failed: expected " + opts.expectedHash + " got " + actual,
761
- "atomic-file/integrity"
762
- );
806
+ throw errorFor("integrity", { expected: opts.expectedHash, actual: actual });
763
807
  }
764
808
  }
765
809
  return opts.encoding ? buf.toString(opts.encoding) : buf;
766
810
  }
767
811
 
812
+ // Atomic-file's own reads route through fdSafeReadSync with an errorFor
813
+ // that reproduces this module's exact codes + messages (a pure refactor).
814
+ function _readSyncCore(filepath, opts) {
815
+ return fdSafeReadSync(filepath, {
816
+ mode: 0o600,
817
+ maxBytes: opts.maxBytes,
818
+ expectedHash: opts.expectedHash,
819
+ encoding: opts.encoding,
820
+ errorFor: function (kind, detail) {
821
+ if (kind === "enoent") {
822
+ var e = new AtomicFileError("file not found: " + filepath, "atomic-file/not-found");
823
+ e.code = "ENOENT";
824
+ return e;
825
+ }
826
+ if (kind === "too-large") {
827
+ return new AtomicFileError(
828
+ "file size " + detail.size + " > maxBytes " + detail.max, "atomic-file/too-large");
829
+ }
830
+ if (kind === "short-read") {
831
+ return new AtomicFileError(
832
+ "short read: " + detail.read + " of " + detail.size + " bytes", "atomic-file/short-read");
833
+ }
834
+ if (kind === "integrity") {
835
+ return new AtomicFileError(
836
+ "integrity check failed: expected " + detail.expected + " got " + detail.actual,
837
+ "atomic-file/integrity");
838
+ }
839
+ return new AtomicFileError("atomic-file: " + kind, "atomic-file/" + kind);
840
+ },
841
+ });
842
+ }
843
+
768
844
  /**
769
845
  * @primitive b.atomicFile.writeJson
770
846
  * @signature b.atomicFile.writeJson(filepath, value, opts)
@@ -1066,6 +1142,7 @@ module.exports = {
1066
1142
  writeSync: writeSync,
1067
1143
  read: read,
1068
1144
  readSync: readSync,
1145
+ fdSafeReadSync: fdSafeReadSync,
1069
1146
  writeJson: writeJson,
1070
1147
  readJson: readJson,
1071
1148
  copy: copy,
@@ -38,6 +38,7 @@ var C = require("./constants");
38
38
  var clusterStorage = require("./cluster-storage");
39
39
  var frameworkSchema = require("./framework-schema");
40
40
  var sql = require("./sql");
41
+ var safeSql = require("./safe-sql");
41
42
  var { sha3Hash } = require("./crypto");
42
43
 
43
44
  // b.sql opts for the chain read SQL these primitives compose. The reader
@@ -135,7 +136,7 @@ function computeRowHash(prevHash, rowFields, nonce) {
135
136
 
136
137
  /**
137
138
  * @primitive b.auditChain.getChainTip
138
- * @signature b.auditChain.getChainTip(queryOneAsync, tableName)
139
+ * @signature b.auditChain.getChainTip(queryOneAsync, tableName, opts?)
139
140
  * @since 0.4.0
140
141
  * @related b.auditChain.verifyChain, b.auditChain.computeRowHash
141
142
  *
@@ -146,6 +147,14 @@ function computeRowHash(prevHash, rowFields, nonce) {
146
147
  * drivers can use any await-able query function of the shape
147
148
  * `async (sql, params?) -> row | null`.
148
149
  *
150
+ * Pass `{ chainKey, keyValue }` to scope the tip to one partition of a
151
+ * multi-chain table (one chain per account / device / tenant) — the tip read
152
+ * filters `WHERE <chainKey> = ?` with the value bound, never interpolated.
153
+ *
154
+ * @opts
155
+ * chainKey: string, // partition column for a multi-chain table
156
+ * keyValue: any, // the partition value to scope the tip to (bound)
157
+ *
149
158
  * @example
150
159
  * async function queryOne(sql) {
151
160
  * var rows = await myDriver.query(sql);
@@ -154,16 +163,22 @@ function computeRowHash(prevHash, rowFields, nonce) {
154
163
  * var tip = await b.auditChain.getChainTip(queryOne, "audit_log");
155
164
  * // → { prevHash: "<128-char hex>", counter: 4217 }
156
165
  */
157
- async function getChainTip(queryOneAsync, tableName) {
166
+ async function getChainTip(queryOneAsync, tableName, opts) {
167
+ opts = opts || {};
158
168
  // Emit a BARE logical table name — the operator-supplied reader routes
159
169
  // through clusterStorage, which rewrites bare framework names to the
160
170
  // configured-prefix form and placeholderizes. b.sql quotes the camelCase
161
- // columns + runs the output validator.
162
- var built = sql.select(tableName, _sqlOpts())
171
+ // columns + runs the output validator. A chainKey scopes the tip to one
172
+ // partition; the key value binds as a ? placeholder.
173
+ var q = sql.select(tableName, _sqlOpts())
163
174
  .columns(["rowHash", "monotonicCounter"])
164
175
  .orderBy("monotonicCounter", "desc")
165
- .limit(1)
166
- .toSql();
176
+ .limit(1);
177
+ if (opts.chainKey) {
178
+ safeSql.validateIdentifier(opts.chainKey);
179
+ q = q.where(opts.chainKey, opts.keyValue);
180
+ }
181
+ var built = q.toSql();
167
182
  var row = await queryOneAsync(built.sql, built.params);
168
183
  if (!row) return { prevHash: ZERO_HASH, counter: 0 };
169
184
  // Normalize driver shape (Postgres returns BIGINT monotonicCounter as a
@@ -192,60 +207,30 @@ async function getChainTip(queryOneAsync, tableName) {
192
207
  * after a successful archive and lets the chain math survive deletion
193
208
  * of historical rows without the archive bundle as source of truth.
194
209
  *
210
+ * Pass `{ chainKey }` to verify a MULTI-chain table partitioned by a key
211
+ * column (one chain per account / device / tenant): each key's sub-chain is
212
+ * walked independently from `ZERO_HASH`, and the first break in any key returns
213
+ * `{ ok:false, chainKey, breakAt, ... }`. Under `chainKey`, `maxRows` is
214
+ * per-sub-chain and `maxChains` bounds the partition fan-out, failing closed
215
+ * when exceeded. The `audit_log` purge-anchor logic is single-chain-only and
216
+ * is skipped when a `chainKey` is given.
217
+ *
195
218
  * @opts
196
- * {
197
- * maxRows?: number, // stop after N rows (default: walk every row)
198
- * }
219
+ * maxRows: number, // stop after N rows per (sub-)chain (default: walk every row)
220
+ * chainKey: string, // partition column verify each sub-chain independently
221
+ * maxChains: number, // max partitions to verify under chainKey (default 100000; fails closed)
199
222
  *
200
223
  * @example
201
224
  * async function queryAll(sql) { return await myDriver.query(sql); }
202
225
  * var result = await b.auditChain.verifyChain(queryAll, "audit_log", {});
203
226
  * // → { ok: true, table: "audit_log", rowsVerified: 4217, lastHash: "<hex>" }
204
227
  */
205
- async function verifyChain(queryAllAsync, tableName, opts) {
206
- opts = opts || {};
207
-
208
- var prevHash = ZERO_HASH;
209
- var skipBeforeCounter = 0;
210
- if (tableName === "audit_log") {
211
- var anchor;
212
- try {
213
- // External-only table whose LOGICAL name IS the `_blamejs_`-prefixed
214
- // name (self-mapped in LOCAL_TO_EXTERNAL), passed bare so the reader's
215
- // clusterStorage rewrites it; the 'audit' scope binds as a ? param.
216
- // allow:hand-rolled-sql — bare logical key.
217
- var anchorBuilt = sql.select("_blamejs_audit_purge_anchor", _sqlOpts()) // allow:hand-rolled-sql
218
- .columns(["lastPurgedCounter", "lastPurgedRowHash"])
219
- .where("scope", "audit")
220
- .toSql();
221
- anchor = await queryAllAsync(anchorBuilt.sql, anchorBuilt.params);
222
- } catch (_e) {
223
- // Anchor table may not exist on a deployment that has never been
224
- // through a purge. Treat as no anchor.
225
- anchor = [];
226
- }
227
- if (Array.isArray(anchor) && anchor.length > 0) {
228
- prevHash = anchor[0].lastPurgedRowHash;
229
- skipBeforeCounter = Number(anchor[0].lastPurgedCounter);
230
- }
231
- }
232
-
233
- var rowsBuilt = sql.select(tableName, _sqlOpts())
234
- .orderBy("monotonicCounter", "asc")
235
- .toSql();
236
- var rows = await queryAllAsync(rowsBuilt.sql, rowsBuilt.params);
237
- // Normalize driver shape before hashing: node-postgres returns BIGINT
238
- // columns (recordedAt / monotonicCounter) as strings, which would hash
239
- // differently from the numbers the chain-writer signed — the chain only
240
- // verified on SQLite without this. coerceRow makes the recompute
241
- // type-stable across backends (no-op on already-numeric SQLite rows).
242
- rows = frameworkSchema.coerceRows(rows);
243
- if (skipBeforeCounter > 0) {
244
- rows = rows.filter(function (r) {
245
- return Number(r.monotonicCounter) > skipBeforeCounter;
246
- });
247
- }
248
-
228
+ // Walk one (sub-)chain forward from startPrevHash, recomputing each row's
229
+ // hash. Returns the same { ok, table, rowsVerified, lastHash | breakAt... }
230
+ // shape verifyChain documents. Shared by the single-chain path and each
231
+ // per-key partition.
232
+ function _walkRows(rows, tableName, startPrevHash, opts) {
233
+ var prevHash = startPrevHash;
249
234
  if (rows.length === 0) {
250
235
  return { ok: true, table: tableName, rowsVerified: 0, lastHash: prevHash };
251
236
  }
@@ -293,6 +278,101 @@ async function verifyChain(queryAllAsync, tableName, opts) {
293
278
  return { ok: true, table: tableName, rowsVerified: rows.length, lastHash: prevHash };
294
279
  }
295
280
 
281
+ async function verifyChain(queryAllAsync, tableName, opts) {
282
+ opts = opts || {};
283
+
284
+ // Multi-chain table: verify each partition independently. Each key's
285
+ // sub-chain anchors at ZERO_HASH and is walked in monotonic-counter order;
286
+ // the first break in ANY key returns { ok:false, chainKey, ... }. maxRows is
287
+ // per-sub-chain; maxChains bounds the partition fan-out (fails closed when
288
+ // exceeded). The audit_log purge-anchor logic is single-chain-only, so it is
289
+ // skipped under a chainKey.
290
+ if (opts.chainKey) {
291
+ safeSql.validateIdentifier(opts.chainKey);
292
+ var keysBuilt = sql.select(tableName, _sqlOpts())
293
+ .distinct()
294
+ .columns([opts.chainKey])
295
+ .orderBy(opts.chainKey, "asc")
296
+ .toSql();
297
+ // coerce so a Postgres INTEGER/BIGINT chainKey is type-stable in the
298
+ // reported break-shape and the per-key WHERE bind, matching SQLite.
299
+ var keyRows = frameworkSchema.coerceRows(await queryAllAsync(keysBuilt.sql, keysBuilt.params));
300
+ var maxChains = (typeof opts.maxChains === "number" && opts.maxChains > 0) ? opts.maxChains : 100000; // allow:numeric-opt-Infinity — partition fan-out cap; non-number / <=0 falls back to the default
301
+ if (keyRows.length > maxChains) {
302
+ return {
303
+ ok: false,
304
+ table: tableName,
305
+ rowsVerified: 0,
306
+ reason: "too many chains: " + keyRows.length + " partitions exceeds maxChains " + maxChains,
307
+ };
308
+ }
309
+ var totalVerified = 0;
310
+ var lastHashByKey = {};
311
+ for (var ki = 0; ki < keyRows.length; ki++) {
312
+ var keyValue = keyRows[ki][opts.chainKey];
313
+ var rowsBuiltK = sql.select(tableName, _sqlOpts())
314
+ .where(opts.chainKey, keyValue)
315
+ .orderBy("monotonicCounter", "asc")
316
+ .toSql();
317
+ var rowsK = frameworkSchema.coerceRows(await queryAllAsync(rowsBuiltK.sql, rowsBuiltK.params));
318
+ var resK = _walkRows(rowsK, tableName, ZERO_HASH, opts);
319
+ if (!resK.ok) { resK.chainKey = keyValue; return resK; }
320
+ totalVerified += resK.rowsVerified;
321
+ lastHashByKey[String(keyValue)] = resK.lastHash;
322
+ }
323
+ return {
324
+ ok: true,
325
+ table: tableName,
326
+ rowsVerified: totalVerified,
327
+ chains: keyRows.length,
328
+ lastHashByKey: lastHashByKey,
329
+ };
330
+ }
331
+
332
+ var prevHash = ZERO_HASH;
333
+ var skipBeforeCounter = 0;
334
+ if (tableName === "audit_log") {
335
+ var anchor;
336
+ try {
337
+ // External-only table whose LOGICAL name IS the `_blamejs_`-prefixed
338
+ // name (self-mapped in LOCAL_TO_EXTERNAL), passed bare so the reader's
339
+ // clusterStorage rewrites it; the 'audit' scope binds as a ? param.
340
+ // allow:hand-rolled-sql — bare logical key.
341
+ var anchorBuilt = sql.select("_blamejs_audit_purge_anchor", _sqlOpts()) // allow:hand-rolled-sql
342
+ .columns(["lastPurgedCounter", "lastPurgedRowHash"])
343
+ .where("scope", "audit")
344
+ .toSql();
345
+ anchor = await queryAllAsync(anchorBuilt.sql, anchorBuilt.params);
346
+ } catch (_e) {
347
+ // Anchor table may not exist on a deployment that has never been
348
+ // through a purge. Treat as no anchor.
349
+ anchor = [];
350
+ }
351
+ if (Array.isArray(anchor) && anchor.length > 0) {
352
+ prevHash = anchor[0].lastPurgedRowHash;
353
+ skipBeforeCounter = Number(anchor[0].lastPurgedCounter);
354
+ }
355
+ }
356
+
357
+ var rowsBuilt = sql.select(tableName, _sqlOpts())
358
+ .orderBy("monotonicCounter", "asc")
359
+ .toSql();
360
+ var rows = await queryAllAsync(rowsBuilt.sql, rowsBuilt.params);
361
+ // Normalize driver shape before hashing: node-postgres returns BIGINT
362
+ // columns (recordedAt / monotonicCounter) as strings, which would hash
363
+ // differently from the numbers the chain-writer signed — the chain only
364
+ // verified on SQLite without this. coerceRow makes the recompute
365
+ // type-stable across backends (no-op on already-numeric SQLite rows).
366
+ rows = frameworkSchema.coerceRows(rows);
367
+ if (skipBeforeCounter > 0) {
368
+ rows = rows.filter(function (r) {
369
+ return Number(r.monotonicCounter) > skipBeforeCounter;
370
+ });
371
+ }
372
+
373
+ return _walkRows(rows, tableName, prevHash, opts);
374
+ }
375
+
296
376
  module.exports = {
297
377
  ZERO_HASH: ZERO_HASH,
298
378
  canonicalize: canonicalize,
@@ -164,20 +164,30 @@ function create(opts) {
164
164
  throw _err("auditDailyReview/audit-query-missing",
165
165
  "auditDailyReview.create: opts.audit.query must be a function");
166
166
  }
167
- validateOpts.optionalFunction(opts.notify,
168
- "auditDailyReview: notify", AuditDailyReviewError, "auditDailyReview/bad-notify");
169
- validateOpts.optionalFunction(opts.classify,
170
- "auditDailyReview: classify", AuditDailyReviewError, "auditDailyReview/bad-classify");
171
- validateOpts.optionalFunction(opts.now,
172
- "auditDailyReview: now", AuditDailyReviewError, "auditDailyReview/bad-now");
173
- validateOpts.optionalNonEmptyString(opts.posture,
174
- "auditDailyReview: posture", AuditDailyReviewError, "auditDailyReview/bad-posture");
175
- validateOpts.optionalNonEmptyString(opts.cron,
176
- "auditDailyReview: cron", AuditDailyReviewError, "auditDailyReview/bad-cron");
177
- validateOpts.optionalPositiveInt(opts.queryLimit,
178
- "auditDailyReview: queryLimit", AuditDailyReviewError, "auditDailyReview/bad-querylimit");
179
- validateOpts.optionalPositiveInt(opts.historyLimit,
180
- "auditDailyReview: historyLimit", AuditDailyReviewError, "auditDailyReview/bad-historylimit");
167
+ validateOpts.shape(opts, {
168
+ audit: { methods: ["query", "safeEmit"] },
169
+ notify: { rule: "optional-function", code: "auditDailyReview/bad-notify" },
170
+ classify: { rule: "optional-function", code: "auditDailyReview/bad-classify" },
171
+ now: { rule: "optional-function", code: "auditDailyReview/bad-now" },
172
+ posture: { rule: "optional-string", code: "auditDailyReview/bad-posture" },
173
+ cron: { rule: "optional-string", code: "auditDailyReview/bad-cron" },
174
+ severityThreshold: { rule: "optional-string", code: "auditDailyReview/bad-severity" },
175
+ queryLimit: { rule: "optional-positive-int", code: "auditDailyReview/bad-querylimit" },
176
+ historyLimit: { rule: "optional-positive-int", code: "auditDailyReview/bad-historylimit" },
177
+ // lookbackHours — positive finite number (hours, not bytes). Bespoke
178
+ // check preserves the auditDailyReview/bad-lookback code the message
179
+ // below depends on; a positive-int token would reject fractional hours.
180
+ lookbackHours: function (value, label) {
181
+ if (value === undefined || value === null) return;
182
+ if (typeof value !== "number" || !isFinite(value) || value <= 0) {
183
+ throw _err("auditDailyReview/bad-lookback",
184
+ "auditDailyReview.create: lookbackHours must be a positive finite number");
185
+ }
186
+ },
187
+ }, "auditDailyReview", AuditDailyReviewError, "auditDailyReview/bad-opts",
188
+ // scheduler is forwarded to the b.scheduler instance at start() and not
189
+ // validated locally at create-time (start() requires it on its own).
190
+ { allow: ["scheduler"] });
181
191
 
182
192
  // lookbackHours — default 24 per PCI DSS 4.0 daily cadence. Caller can
183
193
  // pass weekly / monthly via larger numbers.