@blamejs/blamejs-shop 0.4.56 → 0.4.57

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 (397) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +426 -366
  4. package/lib/vendor/blamejs/.github/codeql/codeql-config.yml +25 -0
  5. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  6. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +1 -1
  7. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +1 -1
  8. package/lib/vendor/blamejs/.github/workflows/ci.yml +13 -13
  9. package/lib/vendor/blamejs/.github/workflows/codeql.yml +8 -7
  10. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +2 -2
  11. package/lib/vendor/blamejs/.github/workflows/release-container.yml +4 -4
  12. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +1 -1
  13. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  14. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  15. package/lib/vendor/blamejs/api-snapshot.json +1381 -4
  16. package/lib/vendor/blamejs/eslint.config.mjs +1 -0
  17. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +4 -1
  18. package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +5 -2
  19. package/lib/vendor/blamejs/examples/wiki/routes/pages.js +4 -1
  20. package/lib/vendor/blamejs/fuzz/guard-text.fuzz.js +20 -0
  21. package/lib/vendor/blamejs/index.js +2 -0
  22. package/lib/vendor/blamejs/lib/a2a-tasks.js +7 -23
  23. package/lib/vendor/blamejs/lib/acme.js +6 -5
  24. package/lib/vendor/blamejs/lib/agent-event-bus.js +5 -4
  25. package/lib/vendor/blamejs/lib/agent-idempotency.js +2 -5
  26. package/lib/vendor/blamejs/lib/agent-orchestrator.js +2 -5
  27. package/lib/vendor/blamejs/lib/agent-saga.js +3 -5
  28. package/lib/vendor/blamejs/lib/agent-tenant.js +2 -5
  29. package/lib/vendor/blamejs/lib/ai-adverse-decision.js +2 -15
  30. package/lib/vendor/blamejs/lib/ai-capability.js +1 -6
  31. package/lib/vendor/blamejs/lib/ai-dp.js +1 -5
  32. package/lib/vendor/blamejs/lib/ai-input.js +2 -2
  33. package/lib/vendor/blamejs/lib/ai-pref.js +3 -8
  34. package/lib/vendor/blamejs/lib/ai-quota.js +3 -14
  35. package/lib/vendor/blamejs/lib/api-key.js +37 -28
  36. package/lib/vendor/blamejs/lib/archive-adapters.js +2 -4
  37. package/lib/vendor/blamejs/lib/archive-entry-policy.js +32 -0
  38. package/lib/vendor/blamejs/lib/archive-read.js +5 -17
  39. package/lib/vendor/blamejs/lib/archive-tar-read.js +5 -16
  40. package/lib/vendor/blamejs/lib/archive.js +2 -10
  41. package/lib/vendor/blamejs/lib/arg-parser.js +7 -6
  42. package/lib/vendor/blamejs/lib/asyncapi-traits.js +2 -6
  43. package/lib/vendor/blamejs/lib/atomic-file.js +108 -31
  44. package/lib/vendor/blamejs/lib/audit-chain.js +133 -53
  45. package/lib/vendor/blamejs/lib/audit-daily-review.js +24 -14
  46. package/lib/vendor/blamejs/lib/audit-emit.js +82 -0
  47. package/lib/vendor/blamejs/lib/audit-sign.js +257 -0
  48. package/lib/vendor/blamejs/lib/audit.js +84 -0
  49. package/lib/vendor/blamejs/lib/auth/access-lock.js +5 -27
  50. package/lib/vendor/blamejs/lib/auth/dpop.js +23 -35
  51. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +9 -15
  52. package/lib/vendor/blamejs/lib/auth/jwt-external.js +26 -8
  53. package/lib/vendor/blamejs/lib/auth/jwt.js +13 -15
  54. package/lib/vendor/blamejs/lib/auth/lockout.js +6 -25
  55. package/lib/vendor/blamejs/lib/auth/oauth.js +67 -45
  56. package/lib/vendor/blamejs/lib/auth/oid4vci.js +55 -32
  57. package/lib/vendor/blamejs/lib/auth/oid4vp.js +3 -2
  58. package/lib/vendor/blamejs/lib/auth/openid-federation.js +6 -6
  59. package/lib/vendor/blamejs/lib/auth/passkey.js +3 -3
  60. package/lib/vendor/blamejs/lib/auth/password.js +7 -1
  61. package/lib/vendor/blamejs/lib/auth/saml.js +37 -27
  62. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +2 -14
  63. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +2 -14
  64. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +1 -1
  65. package/lib/vendor/blamejs/lib/auth/status-list.js +7 -7
  66. package/lib/vendor/blamejs/lib/auth/step-up.js +6 -12
  67. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +6 -37
  68. package/lib/vendor/blamejs/lib/backup/bundle.js +11 -18
  69. package/lib/vendor/blamejs/lib/backup/index.js +14 -47
  70. package/lib/vendor/blamejs/lib/bounded-map.js +112 -1
  71. package/lib/vendor/blamejs/lib/breach-deadline.js +1 -11
  72. package/lib/vendor/blamejs/lib/cache.js +7 -18
  73. package/lib/vendor/blamejs/lib/cbor.js +2 -1
  74. package/lib/vendor/blamejs/lib/cdn-cache-control.js +8 -9
  75. package/lib/vendor/blamejs/lib/cert.js +3 -10
  76. package/lib/vendor/blamejs/lib/chain-writer.js +162 -47
  77. package/lib/vendor/blamejs/lib/cli.js +5 -1
  78. package/lib/vendor/blamejs/lib/client-hints.js +7 -9
  79. package/lib/vendor/blamejs/lib/cloud-events.js +40 -31
  80. package/lib/vendor/blamejs/lib/cluster-storage.js +2 -38
  81. package/lib/vendor/blamejs/lib/cms-codec.js +2 -1
  82. package/lib/vendor/blamejs/lib/codepoint-class.js +67 -1
  83. package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +1 -6
  84. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +2 -4
  85. package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -11
  86. package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +21 -28
  87. package/lib/vendor/blamejs/lib/compliance-sanctions.js +2 -14
  88. package/lib/vendor/blamejs/lib/compliance.js +2 -9
  89. package/lib/vendor/blamejs/lib/config-drift.js +2 -12
  90. package/lib/vendor/blamejs/lib/content-digest.js +10 -8
  91. package/lib/vendor/blamejs/lib/cookies.js +5 -11
  92. package/lib/vendor/blamejs/lib/cose.js +19 -11
  93. package/lib/vendor/blamejs/lib/cra-report.js +1 -11
  94. package/lib/vendor/blamejs/lib/crypto-field.js +5 -10
  95. package/lib/vendor/blamejs/lib/crypto.js +120 -3
  96. package/lib/vendor/blamejs/lib/csp.js +235 -3
  97. package/lib/vendor/blamejs/lib/daemon.js +42 -41
  98. package/lib/vendor/blamejs/lib/data-act.js +19 -9
  99. package/lib/vendor/blamejs/lib/db-query.js +6 -40
  100. package/lib/vendor/blamejs/lib/db.js +34 -12
  101. package/lib/vendor/blamejs/lib/dbsc.js +5 -6
  102. package/lib/vendor/blamejs/lib/ddl-change-control.js +18 -14
  103. package/lib/vendor/blamejs/lib/deprecate.js +4 -5
  104. package/lib/vendor/blamejs/lib/did.js +6 -2
  105. package/lib/vendor/blamejs/lib/dsr.js +8 -12
  106. package/lib/vendor/blamejs/lib/external-db-migrate.js +21 -22
  107. package/lib/vendor/blamejs/lib/external-db.js +14 -26
  108. package/lib/vendor/blamejs/lib/fda-21cfr11.js +12 -8
  109. package/lib/vendor/blamejs/lib/fdx.js +22 -18
  110. package/lib/vendor/blamejs/lib/file-upload.js +80 -66
  111. package/lib/vendor/blamejs/lib/flag-evaluation-context.js +5 -8
  112. package/lib/vendor/blamejs/lib/framework-error.js +12 -0
  113. package/lib/vendor/blamejs/lib/framework-schema.js +19 -0
  114. package/lib/vendor/blamejs/lib/fsm.js +7 -12
  115. package/lib/vendor/blamejs/lib/gate-contract.js +869 -38
  116. package/lib/vendor/blamejs/lib/gdpr-ropa.js +4 -13
  117. package/lib/vendor/blamejs/lib/graphql-federation.js +1 -1
  118. package/lib/vendor/blamejs/lib/guard-agent-registry.js +2 -1
  119. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  120. package/lib/vendor/blamejs/lib/guard-archive.js +9 -30
  121. package/lib/vendor/blamejs/lib/guard-auth.js +23 -80
  122. package/lib/vendor/blamejs/lib/guard-cidr.js +20 -96
  123. package/lib/vendor/blamejs/lib/guard-csv.js +135 -196
  124. package/lib/vendor/blamejs/lib/guard-domain.js +23 -106
  125. package/lib/vendor/blamejs/lib/guard-dsn.js +16 -13
  126. package/lib/vendor/blamejs/lib/guard-email.js +46 -53
  127. package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
  128. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +2 -1
  129. package/lib/vendor/blamejs/lib/guard-filename.js +12 -60
  130. package/lib/vendor/blamejs/lib/guard-graphql.js +28 -75
  131. package/lib/vendor/blamejs/lib/guard-html-wcag.js +15 -2
  132. package/lib/vendor/blamejs/lib/guard-html.js +65 -117
  133. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +2 -1
  134. package/lib/vendor/blamejs/lib/guard-image.js +280 -77
  135. package/lib/vendor/blamejs/lib/guard-imap-command.js +8 -9
  136. package/lib/vendor/blamejs/lib/guard-json.js +87 -103
  137. package/lib/vendor/blamejs/lib/guard-jsonpath.js +20 -88
  138. package/lib/vendor/blamejs/lib/guard-jwt.js +32 -114
  139. package/lib/vendor/blamejs/lib/guard-list-id.js +2 -7
  140. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -7
  141. package/lib/vendor/blamejs/lib/guard-mail-compose.js +5 -6
  142. package/lib/vendor/blamejs/lib/guard-mail-move.js +2 -1
  143. package/lib/vendor/blamejs/lib/guard-mail-query.js +5 -3
  144. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +6 -7
  145. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +5 -4
  146. package/lib/vendor/blamejs/lib/guard-markdown.js +76 -110
  147. package/lib/vendor/blamejs/lib/guard-message-id.js +5 -6
  148. package/lib/vendor/blamejs/lib/guard-mime.js +20 -99
  149. package/lib/vendor/blamejs/lib/guard-oauth.js +19 -73
  150. package/lib/vendor/blamejs/lib/guard-pdf.js +65 -72
  151. package/lib/vendor/blamejs/lib/guard-pop3-command.js +12 -13
  152. package/lib/vendor/blamejs/lib/guard-posture-chain.js +2 -1
  153. package/lib/vendor/blamejs/lib/guard-regex.js +24 -99
  154. package/lib/vendor/blamejs/lib/guard-saga-config.js +2 -1
  155. package/lib/vendor/blamejs/lib/guard-shell.js +22 -87
  156. package/lib/vendor/blamejs/lib/guard-smtp-command.js +8 -11
  157. package/lib/vendor/blamejs/lib/guard-sql.js +15 -13
  158. package/lib/vendor/blamejs/lib/guard-stream-args.js +2 -1
  159. package/lib/vendor/blamejs/lib/guard-svg.js +95 -140
  160. package/lib/vendor/blamejs/lib/guard-template.js +23 -80
  161. package/lib/vendor/blamejs/lib/guard-tenant-id.js +2 -1
  162. package/lib/vendor/blamejs/lib/guard-text.js +592 -0
  163. package/lib/vendor/blamejs/lib/guard-time.js +27 -95
  164. package/lib/vendor/blamejs/lib/guard-uuid.js +21 -93
  165. package/lib/vendor/blamejs/lib/guard-xml.js +76 -106
  166. package/lib/vendor/blamejs/lib/guard-yaml.js +24 -60
  167. package/lib/vendor/blamejs/lib/http-client-cache.js +5 -12
  168. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +2 -4
  169. package/lib/vendor/blamejs/lib/http-client.js +8 -21
  170. package/lib/vendor/blamejs/lib/http-message-signature.js +3 -2
  171. package/lib/vendor/blamejs/lib/i18n-messageformat.js +5 -7
  172. package/lib/vendor/blamejs/lib/i18n.js +83 -26
  173. package/lib/vendor/blamejs/lib/inbox.js +8 -8
  174. package/lib/vendor/blamejs/lib/incident-report.js +3 -21
  175. package/lib/vendor/blamejs/lib/ip-utils.js +49 -6
  176. package/lib/vendor/blamejs/lib/jobs.js +3 -2
  177. package/lib/vendor/blamejs/lib/keychain.js +6 -18
  178. package/lib/vendor/blamejs/lib/legal-hold.js +6 -15
  179. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +44 -112
  180. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +17 -14
  181. package/lib/vendor/blamejs/lib/log-stream-otlp.js +16 -80
  182. package/lib/vendor/blamejs/lib/log-stream-webhook.js +20 -92
  183. package/lib/vendor/blamejs/lib/mail-arc-sign.js +8 -3
  184. package/lib/vendor/blamejs/lib/mail-arf.js +3 -2
  185. package/lib/vendor/blamejs/lib/mail-auth.js +40 -66
  186. package/lib/vendor/blamejs/lib/mail-bimi.js +19 -39
  187. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +3 -2
  188. package/lib/vendor/blamejs/lib/mail-dav.js +8 -35
  189. package/lib/vendor/blamejs/lib/mail-deploy.js +6 -9
  190. package/lib/vendor/blamejs/lib/mail-dkim.js +19 -38
  191. package/lib/vendor/blamejs/lib/mail-greylist.js +15 -26
  192. package/lib/vendor/blamejs/lib/mail-helo.js +2 -3
  193. package/lib/vendor/blamejs/lib/mail-journal.js +2 -1
  194. package/lib/vendor/blamejs/lib/mail-mdn.js +4 -3
  195. package/lib/vendor/blamejs/lib/mail-rbl.js +5 -8
  196. package/lib/vendor/blamejs/lib/mail-scan.js +2 -2
  197. package/lib/vendor/blamejs/lib/mail-send-deliver.js +33 -20
  198. package/lib/vendor/blamejs/lib/mail-server-imap.js +32 -87
  199. package/lib/vendor/blamejs/lib/mail-server-jmap.js +35 -51
  200. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +29 -83
  201. package/lib/vendor/blamejs/lib/mail-server-mx.js +33 -74
  202. package/lib/vendor/blamejs/lib/mail-server-net.js +177 -0
  203. package/lib/vendor/blamejs/lib/mail-server-pop3.js +30 -83
  204. package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +30 -6
  205. package/lib/vendor/blamejs/lib/mail-server-submission.js +34 -73
  206. package/lib/vendor/blamejs/lib/mail-server-tls.js +89 -0
  207. package/lib/vendor/blamejs/lib/mail-spam-score.js +7 -8
  208. package/lib/vendor/blamejs/lib/mail-store.js +3 -2
  209. package/lib/vendor/blamejs/lib/mail.js +6 -11
  210. package/lib/vendor/blamejs/lib/markup-escape.js +31 -0
  211. package/lib/vendor/blamejs/lib/markup-tokenizer.js +54 -0
  212. package/lib/vendor/blamejs/lib/mcp-tool-registry.js +26 -23
  213. package/lib/vendor/blamejs/lib/mcp.js +1 -1
  214. package/lib/vendor/blamejs/lib/mdoc.js +11 -12
  215. package/lib/vendor/blamejs/lib/metrics.js +32 -30
  216. package/lib/vendor/blamejs/lib/middleware/age-gate.js +3 -23
  217. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +11 -22
  218. package/lib/vendor/blamejs/lib/middleware/assetlinks.js +2 -7
  219. package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +2 -1
  220. package/lib/vendor/blamejs/lib/middleware/body-parser.js +31 -48
  221. package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +7 -10
  222. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +2 -10
  223. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +13 -2
  224. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -26
  225. package/lib/vendor/blamejs/lib/middleware/deny-response.js +19 -1
  226. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +7 -0
  227. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +4 -20
  228. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +20 -28
  229. package/lib/vendor/blamejs/lib/middleware/scim-server.js +3 -2
  230. package/lib/vendor/blamejs/lib/middleware/security-headers.js +9 -1
  231. package/lib/vendor/blamejs/lib/middleware/security-txt.js +2 -6
  232. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +12 -27
  233. package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +2 -7
  234. package/lib/vendor/blamejs/lib/migrations.js +4 -13
  235. package/lib/vendor/blamejs/lib/mime-parse.js +34 -17
  236. package/lib/vendor/blamejs/lib/module-loader.js +44 -0
  237. package/lib/vendor/blamejs/lib/money.js +105 -0
  238. package/lib/vendor/blamejs/lib/mtls-ca.js +116 -36
  239. package/lib/vendor/blamejs/lib/network-byte-quota.js +4 -18
  240. package/lib/vendor/blamejs/lib/network-dane.js +8 -6
  241. package/lib/vendor/blamejs/lib/network-dns-resolver.js +97 -6
  242. package/lib/vendor/blamejs/lib/network-dnssec.js +16 -16
  243. package/lib/vendor/blamejs/lib/network-heartbeat.js +3 -2
  244. package/lib/vendor/blamejs/lib/network-smtp-policy.js +29 -41
  245. package/lib/vendor/blamejs/lib/network-tls.js +40 -42
  246. package/lib/vendor/blamejs/lib/nis2-report.js +1 -11
  247. package/lib/vendor/blamejs/lib/nonce-store.js +81 -3
  248. package/lib/vendor/blamejs/lib/numeric-bounds.js +22 -8
  249. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +2 -6
  250. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +5 -45
  251. package/lib/vendor/blamejs/lib/object-store/gcs.js +8 -71
  252. package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -5
  253. package/lib/vendor/blamejs/lib/object-store/http-request.js +128 -0
  254. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +2 -1
  255. package/lib/vendor/blamejs/lib/object-store/sigv4.js +9 -77
  256. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -25
  257. package/lib/vendor/blamejs/lib/observability.js +95 -0
  258. package/lib/vendor/blamejs/lib/openapi-paths-builder.js +7 -3
  259. package/lib/vendor/blamejs/lib/otel-export.js +7 -10
  260. package/lib/vendor/blamejs/lib/outbox.js +43 -37
  261. package/lib/vendor/blamejs/lib/pagination.js +11 -15
  262. package/lib/vendor/blamejs/lib/parsers/safe-env.js +5 -4
  263. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +10 -4
  264. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +11 -9
  265. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +2 -2
  266. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +7 -6
  267. package/lib/vendor/blamejs/lib/pick.js +63 -5
  268. package/lib/vendor/blamejs/lib/pipl-cn.js +69 -59
  269. package/lib/vendor/blamejs/lib/privacy-pass.js +8 -6
  270. package/lib/vendor/blamejs/lib/problem-details.js +2 -5
  271. package/lib/vendor/blamejs/lib/pubsub.js +4 -8
  272. package/lib/vendor/blamejs/lib/redact.js +2 -1
  273. package/lib/vendor/blamejs/lib/render.js +4 -2
  274. package/lib/vendor/blamejs/lib/request-helpers.js +133 -6
  275. package/lib/vendor/blamejs/lib/restore.js +5 -22
  276. package/lib/vendor/blamejs/lib/retention.js +3 -5
  277. package/lib/vendor/blamejs/lib/safe-async.js +457 -0
  278. package/lib/vendor/blamejs/lib/safe-buffer.js +137 -6
  279. package/lib/vendor/blamejs/lib/safe-decompress.js +2 -1
  280. package/lib/vendor/blamejs/lib/safe-dns.js +2 -1
  281. package/lib/vendor/blamejs/lib/safe-ical.js +12 -26
  282. package/lib/vendor/blamejs/lib/safe-json.js +7 -8
  283. package/lib/vendor/blamejs/lib/safe-jsonpath.js +6 -5
  284. package/lib/vendor/blamejs/lib/safe-mime.js +25 -29
  285. package/lib/vendor/blamejs/lib/safe-redirect.js +2 -5
  286. package/lib/vendor/blamejs/lib/safe-schema.js +7 -6
  287. package/lib/vendor/blamejs/lib/safe-sql.js +126 -0
  288. package/lib/vendor/blamejs/lib/safe-vcard.js +12 -26
  289. package/lib/vendor/blamejs/lib/sandbox-worker.js +9 -2
  290. package/lib/vendor/blamejs/lib/sandbox.js +3 -2
  291. package/lib/vendor/blamejs/lib/scheduler.js +5 -12
  292. package/lib/vendor/blamejs/lib/sec-cyber.js +82 -37
  293. package/lib/vendor/blamejs/lib/seeders.js +4 -11
  294. package/lib/vendor/blamejs/lib/self-update.js +92 -69
  295. package/lib/vendor/blamejs/lib/session-device-binding.js +112 -66
  296. package/lib/vendor/blamejs/lib/session.js +194 -6
  297. package/lib/vendor/blamejs/lib/sql.js +225 -78
  298. package/lib/vendor/blamejs/lib/sse.js +6 -10
  299. package/lib/vendor/blamejs/lib/static.js +136 -98
  300. package/lib/vendor/blamejs/lib/storage.js +4 -2
  301. package/lib/vendor/blamejs/lib/structured-fields.js +275 -16
  302. package/lib/vendor/blamejs/lib/tenant-quota.js +2 -20
  303. package/lib/vendor/blamejs/lib/tsa.js +11 -15
  304. package/lib/vendor/blamejs/lib/validate-opts.js +154 -8
  305. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +30 -48
  306. package/lib/vendor/blamejs/lib/vault-aad.js +3 -2
  307. package/lib/vendor/blamejs/lib/vc.js +2 -7
  308. package/lib/vendor/blamejs/lib/vex.js +35 -13
  309. package/lib/vendor/blamejs/lib/web-push-vapid.js +23 -20
  310. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +706 -0
  311. package/lib/vendor/blamejs/lib/webhook.js +43 -18
  312. package/lib/vendor/blamejs/lib/websocket-channels.js +9 -7
  313. package/lib/vendor/blamejs/lib/websocket.js +7 -3
  314. package/lib/vendor/blamejs/lib/worm.js +2 -3
  315. package/lib/vendor/blamejs/lib/ws-client.js +8 -10
  316. package/lib/vendor/blamejs/package.json +1 -1
  317. package/lib/vendor/blamejs/release-notes/v0.15.13.json +81 -0
  318. package/lib/vendor/blamejs/scripts/check-changelog-extract.js +1 -1
  319. package/lib/vendor/blamejs/test/00-primitives.js +136 -7
  320. package/lib/vendor/blamejs/test/10-state.js +9 -3
  321. package/lib/vendor/blamejs/test/30-chain.js +40 -0
  322. package/lib/vendor/blamejs/test/helpers/check.js +18 -0
  323. package/lib/vendor/blamejs/test/helpers/db.js +4 -0
  324. package/lib/vendor/blamejs/test/helpers/index.js +1 -0
  325. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +2 -1
  326. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +2 -1
  327. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +8 -1
  328. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +1 -1
  329. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +2 -1
  330. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +269 -0
  331. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +149 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +51 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +88 -0
  334. package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +55 -1
  335. package/lib/vendor/blamejs/test/layer-0-primitives/backup-object-store-adapter.test.js +2 -2
  336. package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +1 -1
  337. package/lib/vendor/blamejs/test/layer-0-primitives/bounded-map.test.js +129 -0
  338. package/lib/vendor/blamejs/test/layer-0-primitives/chain-writer-multichain.test.js +107 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +12 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +2788 -3214
  341. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +78 -0
  342. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +63 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +2 -1
  344. package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +50 -0
  345. package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +1 -1
  346. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +2 -1
  347. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-resolve-opts.test.js +76 -0
  348. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +9 -0
  349. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract-content-gate.test.js +290 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +84 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +78 -0
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +23 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-gate-disposition-coverage.test.js +93 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +60 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +184 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +54 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +10 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +45 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +101 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +18 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +76 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-text.test.js +365 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +35 -0
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +36 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +20 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +83 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +10 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +39 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +36 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +17 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +39 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +17 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/mime-parse.test.js +106 -0
  376. package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +17 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-revocation.test.js +98 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-release.test.js +77 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +48 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-memory-getorinsert.test.js +100 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +88 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +278 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +37 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +14 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +19 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +1 -1
  387. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +2 -1
  388. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +18 -0
  389. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +1 -1
  390. package/lib/vendor/blamejs/test/layer-0-primitives/session-valid-from.test.js +73 -0
  391. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +100 -0
  392. package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +80 -0
  393. package/lib/vendor/blamejs/test/layer-0-primitives/validate-opts-shape.test.js +235 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +374 -0
  395. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +75 -8
  396. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +3 -3
  397. package/package.json +1 -1
@@ -1887,6 +1887,45 @@ async function testCheckpointVerify() {
1887
1887
  }
1888
1888
  }
1889
1889
 
1890
+ // Regression: a fire-and-forget checkpoint launched by db.close() reads the
1891
+ // chain tip from the open database, then its deferred insert resolves the live
1892
+ // db handle at resume time. If a fresh database opened in between, the old
1893
+ // tip's checkpoint must NOT be anchored into that different/absent database
1894
+ // (it would forge a checkpoint signed under the prior keypair into another db).
1895
+ // Reproduce deterministically: tear the db down (bumping the db generation)
1896
+ // between the tip read and the insert — auditSign.sign() sits exactly there in
1897
+ // checkpoint(). The checkpoint must fail closed (return null, never throw, never
1898
+ // write) instead of inserting against the torn-down/replaced database.
1899
+ async function testCheckpointCrossGenerationRefused() {
1900
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-ckptgen-"));
1901
+ var realGen = b.db._dbGeneration;
1902
+ try {
1903
+ await setupTestDb(tmpDir);
1904
+ b.audit.registerNamespace("test");
1905
+ await b.audit.record({ action: "test.event", outcome: "success" });
1906
+
1907
+ // Simulate the db handle being closed/replaced between the tip read and
1908
+ // the insert: dbGeneration() returns one value when checkpoint() binds at
1909
+ // entry, and a changed value at the pre-insert re-check. The checkpoint
1910
+ // must fail closed — return null and write nothing.
1911
+ var n = 0;
1912
+ b.db._dbGeneration = function () { n += 1; return n <= 1 ? 1000 : 1001; };
1913
+ var result = await b.audit.checkpoint();
1914
+ b.db._dbGeneration = realGen;
1915
+
1916
+ check("cross-generation checkpoint returns null", result === null);
1917
+ var after = await b.audit.verifyCheckpoints();
1918
+ check("cross-generation checkpoint wrote nothing", after.ok === true && after.checkpointsVerified === 0);
1919
+
1920
+ // Control: a stable-generation checkpoint still anchors normally.
1921
+ var ok = await b.audit.checkpoint();
1922
+ check("stable-generation checkpoint still anchors", ok && typeof ok._id === "string");
1923
+ } finally {
1924
+ b.db._dbGeneration = realGen;
1925
+ await teardownTestDb(tmpDir);
1926
+ }
1927
+ }
1928
+
1890
1929
  async function testCheckpointTamperDetect() {
1891
1930
  var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-cdetect-"));
1892
1931
  try {
@@ -2062,6 +2101,7 @@ async function run() {
2062
2101
  // checkpoint sign / verify / tamper / rollback
2063
2102
  await testCheckpointSign();
2064
2103
  await testCheckpointVerify();
2104
+ await testCheckpointCrossGenerationRefused();
2065
2105
  await testCheckpointTamperDetect();
2066
2106
  await testRollbackDetection();
2067
2107
  }
@@ -28,9 +28,27 @@ function addExternalChecks(n) {
28
28
  if (typeof n === "number" && isFinite(n) && n >= 0) _checks += n;
29
29
  }
30
30
 
31
+ // formatErr — render a thrown error as a single-line, bounded diagnostic for a
32
+ // test runner's failure catch. A thrown error's message/stack can carry a test
33
+ // fixture's bytes verbatim; replacing CR/LF (a recognized log-injection
34
+ // barrier) keeps the "FAIL:" line on one row so a fixture value can't forge
35
+ // extra log lines. The newline .replace() is what breaks the log-injection
36
+ // data flow; the tab/run-collapse + length bound are cosmetic.
37
+ function formatErr(e) {
38
+ var raw = (e && typeof e.stack === "string" && e.stack) ||
39
+ (e && typeof e.message === "string" && e.message) ||
40
+ String(e);
41
+ var oneLine = raw
42
+ .replace(/[\r\n]+/g, " ")
43
+ .replace(/\t+/g, " ")
44
+ .replace(/ {2,}/g, " ");
45
+ return oneLine.length > 2000 ? oneLine.slice(0, 2000) + "..." : oneLine;
46
+ }
47
+
31
48
  module.exports = {
32
49
  check: check,
33
50
  getChecks: getChecks,
34
51
  resetChecksForTest: resetChecksForTest,
35
52
  addExternalChecks: addExternalChecks,
53
+ formatErr: formatErr,
36
54
  };
@@ -68,6 +68,10 @@ async function teardownTestDb(tmpDir) {
68
68
  // Drain audit handler buffered emissions BEFORE close so pending
69
69
  // rows land in audit_log rather than leaking into the next test's DB.
70
70
  try { await b.audit.flush(); } catch (_e) {}
71
+ // Anchor the final checkpoint synchronously while this db is still open, so
72
+ // close()'s own fire-and-forget checkpoint no-ops (skipIfUnchanged) and no
73
+ // detached checkpoint promise straddles the db boundary into the next test.
74
+ try { await b.audit.checkpoint({ skipIfUnchanged: true }); } catch (_e) {}
71
75
  try { b.db.close(); } catch (_e) {}
72
76
  b.audit._resetForTest();
73
77
  b.db._resetForTest();
@@ -43,6 +43,7 @@ module.exports = {
43
43
  getChecks: _check.getChecks,
44
44
  resetChecksForTest: _check.resetChecksForTest,
45
45
  addExternalChecks: _check.addExternalChecks,
46
+ formatErr: _check.formatErr,
46
47
 
47
48
  // DB fixtures
48
49
  setupTestDb: _db.setupTestDb,
@@ -323,7 +323,8 @@ async function run() {
323
323
  "_blamejs_audit_tip", "_blamejs_consent_tip", "_blamejs_audit_purge_anchor",
324
324
  "_blamejs_scheduler_ticks", "_blamejs_rate_limit_counters",
325
325
  "_blamejs_pubsub_messages", "_blamejs_api_encrypt_nonces", "_blamejs_api_keys",
326
- "_blamejs_sessions", "_blamejs_jobs", "_blamejs_cache", "_blamejs_cache_tags",
326
+ "_blamejs_sessions", "_blamejs_session_valid_from", "_blamejs_jobs",
327
+ "_blamejs_cache", "_blamejs_cache_tags",
327
328
  "_blamejs_seeders", "_blamejs_seeders_lock", "_blamejs_break_glass_policies",
328
329
  "_blamejs_break_glass_grants", "_blamejs_leader", "_blamejs_cluster_state",
329
330
  ].map(function (t) { return "DROP TABLE IF EXISTS " + t + " CASCADE;"; }).join("\n");
@@ -254,7 +254,8 @@ var FRAMEWORK_TABLES = [
254
254
  "_blamejs_audit_tip", "_blamejs_consent_tip", "_blamejs_audit_purge_anchor",
255
255
  "_blamejs_scheduler_ticks", "_blamejs_rate_limit_counters",
256
256
  "_blamejs_pubsub_messages", "_blamejs_api_encrypt_nonces", "_blamejs_api_keys",
257
- "_blamejs_sessions", "_blamejs_jobs", "_blamejs_cache", "_blamejs_cache_tags",
257
+ "_blamejs_sessions", "_blamejs_session_valid_from", "_blamejs_jobs",
258
+ "_blamejs_cache", "_blamejs_cache_tags",
258
259
  "_blamejs_seeders", "_blamejs_seeders_lock", "_blamejs_break_glass_policies",
259
260
  "_blamejs_break_glass_grants", "_blamejs_leader", "_blamejs_cluster_state",
260
261
  // app-side table for break-glass + K_row storage round-trips
@@ -209,6 +209,13 @@ var MYSQL_DDL = [
209
209
  "`createdAt` BIGINT NOT NULL, " +
210
210
  "`expiresAt` BIGINT NOT NULL, " +
211
211
  "`lastActivity` BIGINT NOT NULL)",
212
+ // _blamejs_session_valid_from — per-subject not-before invalidation. Mirrors
213
+ // framework-schema._sessionValidFromDDL("mysql"): VARCHAR key, BIGINT epochs.
214
+ "DROP TABLE IF EXISTS `_blamejs_session_valid_from`",
215
+ "CREATE TABLE `_blamejs_session_valid_from` (" +
216
+ "`subjectHash` VARCHAR(191) PRIMARY KEY, " +
217
+ "`validFromEpoch` BIGINT NOT NULL, " +
218
+ "`updatedAt` BIGINT NOT NULL)",
212
219
  // _blamejs_api_encrypt_nonces — replay-protection store. nonceHash is the
213
220
  // PRIMARY KEY, so the ON DUPLICATE KEY UPDATE no-op fold makes the first
214
221
  // insert win (affectedRows=1) and a replay no-op (affectedRows=0).
@@ -241,7 +248,7 @@ var MYSQL_DDL = [
241
248
  var DROP_ALL = [
242
249
  "_blamejs_cache", "_blamejs_cache_tags", "_blamejs_audit_tip",
243
250
  "_blamejs_consent_tip", "_blamejs_audit_log", "_blamejs_consent_log",
244
- "_blamejs_sessions", "_blamejs_api_encrypt_nonces",
251
+ "_blamejs_sessions", "_blamejs_session_valid_from", "_blamejs_api_encrypt_nonces",
245
252
  "_blamejs_rate_limit_counters", "_blamejs_cluster_state",
246
253
  ].map(function (t) { return "DROP TABLE IF EXISTS `" + t + "`"; });
247
254
 
@@ -245,7 +245,7 @@ function _parseBlock(block) {
245
245
  // cache_tags / nonces / rate-limit counters, but ensureSchema materializes
246
246
  // the whole framework surface, so all of it is swept.
247
247
  var FRAMEWORK_TABLES = [
248
- "_blamejs_sessions", "_blamejs_cache", "_blamejs_cache_tags",
248
+ "_blamejs_sessions", "_blamejs_session_valid_from", "_blamejs_cache", "_blamejs_cache_tags",
249
249
  "_blamejs_api_encrypt_nonces", "_blamejs_rate_limit_counters",
250
250
  "_blamejs_audit_log", "_blamejs_consent_log", "_blamejs_audit_checkpoints",
251
251
  "_blamejs_audit_tip", "_blamejs_consent_tip", "_blamejs_audit_purge_anchor",
@@ -138,7 +138,8 @@ var FRAMEWORK_TABLES = [
138
138
  "_blamejs_audit_tip", "_blamejs_consent_tip", "_blamejs_audit_purge_anchor",
139
139
  "_blamejs_scheduler_ticks", "_blamejs_rate_limit_counters",
140
140
  "_blamejs_pubsub_messages", "_blamejs_api_encrypt_nonces", "_blamejs_api_keys",
141
- "_blamejs_sessions", "_blamejs_jobs", "_blamejs_cache", "_blamejs_cache_tags",
141
+ "_blamejs_sessions", "_blamejs_session_valid_from", "_blamejs_jobs",
142
+ "_blamejs_cache", "_blamejs_cache_tags",
142
143
  "_blamejs_seeders", "_blamejs_seeders_lock", "_blamejs_break_glass_policies",
143
144
  "_blamejs_break_glass_grants",
144
145
  ];
@@ -0,0 +1,269 @@
1
+ "use strict";
2
+ /**
3
+ * Live webhook-dispatcher test against the docker Postgres container. The
4
+ * dispatcher's durable store composes b.sql -> b.externalDb, so smoke only
5
+ * ever exercises it on SQLite; this proves the real Postgres dialect path:
6
+ *
7
+ * - declareSchema renders valid Postgres DDL (serial -> BIGSERIAL, the
8
+ * TIMESTAMPTZ columns, the partial pending index) on a real server.
9
+ * - registerEndpoint INSERTs with the secret SEALED at rest (vault: prefix
10
+ * in the actual Postgres row, never the plaintext secret).
11
+ * - dispatch fans out one event into one delivery row per endpoint and the
12
+ * $1..$N-bound INSERT/UPDATE round-trips.
13
+ * - the retry claim TRANSACTION (mark-then-reselect) + the BIGINT `attempts`
14
+ * column coercing back through frameworkSchema for the count comparison.
15
+ * - maxAttempts -> dead-letter and dlq.replay on real Postgres.
16
+ *
17
+ * Delivery HTTP is a stubbed transport (no network); the storage path is real.
18
+ *
19
+ * RUN: node scripts/test-integration.js --skip-service-check webhook-dispatcher-pg
20
+ */
21
+ var spawn = require("node:child_process").spawn;
22
+ var execFileSync = require("node:child_process").execFileSync;
23
+ var fs = require("node:fs");
24
+ var os = require("node:os");
25
+ var path = require("node:path");
26
+ var helpers = require("../helpers");
27
+ var check = helpers.check;
28
+ var services = require("../helpers/services");
29
+ var b = require("../../");
30
+
31
+ var CONTAINER = "blamejs-test-postgres";
32
+ var NULL_SENTINEL = "__BJNULL__";
33
+ var PSQL_ARGS = "psql -U blamejs -d blamejs_test -A -v ON_ERROR_STOP=0 -P null=__BJNULL__ 2>&1";
34
+
35
+ var ENDPOINTS_TABLE = b.frameworkSchema.tableName("webhook_endpoints");
36
+ var DELIVERIES_TABLE = b.frameworkSchema.tableName("webhook_deliveries");
37
+
38
+ // ---- one-shot psql (setup / teardown / out-of-band assertions) ----
39
+ function _psql(sql) {
40
+ var out = execFileSync(
41
+ "docker",
42
+ ["exec", "-i", CONTAINER, "sh", "-c", "psql -U blamejs -d blamejs_test -qtA -P null=__BJNULL__ 2>&1"],
43
+ { input: sql + "\n", stdio: ["pipe", "pipe", "pipe"] }
44
+ ).toString("utf8");
45
+ if (/^ERROR:/m.test(out)) throw new Error("psql failed for [" + sql + "]:\n" + out);
46
+ return out;
47
+ }
48
+
49
+ // ---- persistent-session docker-exec psql driver (faithful to node-postgres:
50
+ // BIGINT comes back as a string; quoted DDL preserves column case) ----
51
+ var _seq = 0;
52
+ function _makeDockerPgDriver() {
53
+ return {
54
+ connect: function () {
55
+ return new Promise(function (resolve, reject) {
56
+ var child = spawn("docker",
57
+ ["exec", "-i", CONTAINER, "sh", "-c", PSQL_ARGS + " ; echo __BLAMEJS_PSQL_EXIT__"],
58
+ { stdio: ["pipe", "pipe", "pipe"] });
59
+ var client = { child: child, buf: "", pending: null, closed: false };
60
+ child.on("error", function (e) { if (client.pending) { var p = client.pending; client.pending = null; p.reject(e); } });
61
+ child.on("close", function () {
62
+ client.closed = true;
63
+ if (client.pending) { var p = client.pending; client.pending = null; p.reject(new Error("psql session closed mid-statement")); }
64
+ });
65
+ child.stdout.on("data", function (chunk) { client.buf += chunk.toString("utf8"); _drain(client); });
66
+ var prime = "__BJ_PRIME__";
67
+ client.pending = { sentinel: prime, resolve: function () { resolve(client); }, reject: reject };
68
+ client.child.stdin.write("\\pset fieldsep '\\t'\n\\pset footer off\n\\echo " + prime + "\n");
69
+ });
70
+ },
71
+ query: function (client, sql, params) {
72
+ var bound = _bindParams(sql, params || []);
73
+ var sentinel = "__BJ_EOR_" + (++_seq) + "__";
74
+ return new Promise(function (resolve, reject) {
75
+ if (client.closed) { reject(new Error("psql session is closed")); return; }
76
+ client.pending = { sentinel: sentinel, resolve: resolve, reject: reject };
77
+ client.child.stdin.write(bound + "\n;\n\\echo " + sentinel + "\n");
78
+ });
79
+ },
80
+ close: function (client) {
81
+ return new Promise(function (resolve) {
82
+ if (client.closed) { resolve(); return; }
83
+ try { client.child.stdin.end("\\q\n"); } catch (_e) {}
84
+ var done = false;
85
+ client.child.on("close", function () { if (!done) { done = true; resolve(); } });
86
+ setTimeout(function () { if (done) return; done = true; try { client.child.kill("SIGKILL"); } catch (_e) {} resolve(); }, 2000);
87
+ });
88
+ },
89
+ };
90
+ }
91
+
92
+ function _drain(client) {
93
+ if (!client.pending) return;
94
+ var sentinel = client.pending.sentinel;
95
+ var marker = "\n" + sentinel + "\n";
96
+ var idx = client.buf.indexOf(marker);
97
+ var startAtZero = client.buf.indexOf(sentinel + "\n") === 0;
98
+ var block;
99
+ if (idx !== -1) { block = client.buf.slice(0, idx); client.buf = client.buf.slice(idx + marker.length); }
100
+ else if (startAtZero) { block = ""; client.buf = client.buf.slice((sentinel + "\n").length); }
101
+ else return;
102
+ var p = client.pending; client.pending = null;
103
+ var parsed;
104
+ try { parsed = _parseBlock(block); } catch (e) { return p.reject(e); }
105
+ if (parsed.error) return p.reject(parsed.error);
106
+ p.resolve({ rows: parsed.rows, rowCount: parsed.rowCount });
107
+ }
108
+
109
+ function _bindOne(v) {
110
+ if (v === null || v === undefined) return "NULL";
111
+ if (typeof v === "number") return String(v);
112
+ if (typeof v === "boolean") return v ? "TRUE" : "FALSE";
113
+ return "'" + String(v).replace(/'/g, "''") + "'";
114
+ }
115
+ function _bindParams(sql, params) {
116
+ return sql.replace(/\$(\d+)/g, function (_m, n) {
117
+ var i = Number(n) - 1;
118
+ if (i < 0 || i >= params.length) throw new Error("placeholder $" + n + " has no matching param");
119
+ var v = params[i];
120
+ // whereInArray emits `col = ANY($k)` for postgres with a JS array param;
121
+ // a real node-postgres driver binds it as a postgres array. Replicate
122
+ // that as an ARRAY[...] literal so the text-shim is faithful.
123
+ if (Array.isArray(v)) return "ARRAY[" + v.map(_bindOne).join(",") + "]";
124
+ return _bindOne(v);
125
+ });
126
+ }
127
+
128
+ var _CMD_TAG_RE = /^(INSERT|UPDATE|DELETE|MERGE|SELECT|COPY|MOVE)\b(?:\s+\d+)*\s*$/;
129
+ var _CTRL_TAG_RE = /^(BEGIN|COMMIT|ROLLBACK|SET|RESET|SAVEPOINT|RELEASE|START|CREATE|DROP|ALTER|GRANT|REVOKE|TRUNCATE|COMMENT|DO|CALL|VACUUM|ANALYZE|EXPLAIN|TABLE|SHOW|DISCARD)\b/;
130
+
131
+ function _parseBlock(block) {
132
+ var lines = block.split(/\r?\n/);
133
+ while (lines.length && lines[lines.length - 1] === "") lines.pop();
134
+ for (var i = 0; i < lines.length; i++) {
135
+ var em = /^ERROR:\s+([0-9A-Za-z]{5}):\s*(.*)$/.exec(lines[i]);
136
+ if (em) { var err = new Error("Postgres " + em[1] + ": " + em[2]); err.code = em[1]; return { error: err }; }
137
+ }
138
+ var affected = null, dataLines = [];
139
+ for (var j = 0; j < lines.length; j++) {
140
+ var ln = lines[j];
141
+ if (/^(NOTICE|WARNING|DETAIL|HINT|LINE|LOCATION|CONTEXT|STATEMENT):/.test(ln)) continue;
142
+ var tm = _CMD_TAG_RE.exec(ln);
143
+ if (tm) { var nums = ln.trim().split(/\s+/).slice(1).map(Number); if (nums.length) affected = nums[nums.length - 1]; continue; }
144
+ if (_CTRL_TAG_RE.test(ln) && ln.indexOf("\t") === -1) continue;
145
+ dataLines.push(ln);
146
+ }
147
+ var rows = [];
148
+ if (dataLines.length >= 1) {
149
+ var headers = dataLines[0].split("\t");
150
+ for (var k = 1; k < dataLines.length; k++) {
151
+ var cells = dataLines[k].split("\t"), row = {};
152
+ for (var c = 0; c < headers.length; c++) {
153
+ var cell = cells[c];
154
+ row[headers[c]] = (cell === NULL_SENTINEL || cell === undefined) ? null : cell;
155
+ }
156
+ rows.push(row);
157
+ }
158
+ }
159
+ return { rows: rows, rowCount: (affected !== null) ? affected : rows.length, error: null };
160
+ }
161
+
162
+ // Thin externalDb over the persistent psql session: exactly the query /
163
+ // transaction / dialect surface the dispatcher consumes. transaction runs
164
+ // BEGIN/COMMIT on the same session (the dispatcher's claim path is the only
165
+ // transactional one).
166
+ function _pgExternalDb(client, driver) {
167
+ var xdb = {
168
+ dialect: "postgres",
169
+ query: function (s, p) {
170
+ // The dispatcher binds JS Date params for the timestamp columns; the
171
+ // psql shim inlines params textually, so Dates must become ISO strings
172
+ // (a JS Date.toString() is not a portable TIMESTAMPTZ literal).
173
+ var bound = (p || []).map(function (v) { return v instanceof Date ? v.toISOString() : v; });
174
+ return driver.query(client, s, bound);
175
+ },
176
+ transaction: async function (fn) {
177
+ await driver.query(client, "BEGIN", []);
178
+ try { var r = await fn(xdb); await driver.query(client, "COMMIT", []); return r; }
179
+ catch (e) { try { await driver.query(client, "ROLLBACK", []); } catch (_e) {} throw e; }
180
+ },
181
+ };
182
+ return xdb;
183
+ }
184
+
185
+ function _stubTransport() {
186
+ var calls = []; var nextStatus = 200;
187
+ var fn = function (url, body, headers) { calls.push({ url: url, headers: headers }); return Promise.resolve({ status: nextStatus }); };
188
+ fn.calls = calls; fn.setStatus = function (s) { nextStatus = s; };
189
+ return fn;
190
+ }
191
+
192
+ function _dropTables() {
193
+ _psql("DROP TABLE IF EXISTS " + DELIVERIES_TABLE + " CASCADE; DROP TABLE IF EXISTS " + ENDPOINTS_TABLE + " CASCADE;");
194
+ }
195
+
196
+ async function run() {
197
+ var pg = await services.requireService("postgres");
198
+ if (!pg.ok) throw new Error("postgres unreachable: " + pg.reason);
199
+ _dropTables();
200
+
201
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-wd-pg-"));
202
+ await helpers.setupVaultOnly(tmpDir); // for vault.seal of the per-endpoint secret
203
+
204
+ var driver = _makeDockerPgDriver();
205
+ var client = await driver.connect();
206
+ var xdb = _pgExternalDb(client, driver);
207
+
208
+ try {
209
+ var now = 1700000000000;
210
+ var clock = function () { return now; };
211
+ var transport = _stubTransport();
212
+ var wd = b.webhook.dispatcher({
213
+ externalDb: xdb, httpRequest: transport, maxAttempts: 3,
214
+ retryBackoff: { initialMs: 1000, maxMs: 5000, factor: 2 }, now: clock,
215
+ });
216
+
217
+ await wd.declareSchema();
218
+ check("declareSchema renders valid Postgres DDL", true);
219
+
220
+ var secret = "whsec_pg_secret_value";
221
+ await wd.registerEndpoint({ endpointId: "ep_pg", url: "https://1.1.1.1/hooks", eventTypes: ["invoice.paid"], secret: secret });
222
+ // Secret sealed at rest IN REAL POSTGRES.
223
+ var sealedRow = _psql("SELECT secret_sealed FROM " + ENDPOINTS_TABLE + " WHERE endpoint_id = 'ep_pg';").trim();
224
+ check("secret sealed at rest in Postgres (vault: prefix)", sealedRow.indexOf("vault:") === 0);
225
+ check("plaintext secret NOT in Postgres row", sealedRow.indexOf("whsec_pg_secret_value") === -1);
226
+
227
+ // dispatch → one delivery row, delivered (stub 200).
228
+ var res = await wd.dispatch("invoice.paid", { id: "inv_pg_1", amount: 4200 });
229
+ check("dispatch delivered on Postgres", res.delivered === 1 && res.failed === 0);
230
+ var delivered = await wd.deliveries.list({ status: "delivered" });
231
+ check("delivered row persisted in Postgres", delivered.length === 1);
232
+ check("BIGINT attempts coerced to number 1", delivered[0].attempts === 1);
233
+ check("responseStatus 200 round-trips", delivered[0].responseStatus === 200);
234
+
235
+ // transient failure → stays pending with attempts incremented.
236
+ transport.setStatus(503);
237
+ await wd.dispatch("invoice.paid", { id: "inv_pg_2" });
238
+ var pendingRows = _psql("SELECT count(*) FROM " + DELIVERIES_TABLE + " WHERE status = 'pending';").trim();
239
+ check("transient failure pending in Postgres", pendingRows === "1");
240
+
241
+ // processRetries claim transaction + dead-letter after maxAttempts.
242
+ transport.setStatus(500);
243
+ now += 10000; await wd.processRetries(); // attempt 2
244
+ now += 10000; var r3 = await wd.processRetries(); // attempt 3 → dead
245
+ check("processRetries dead-letters on Postgres", r3.dead === 1);
246
+ var dlq = await wd.dlq.list();
247
+ check("DLQ holds dead delivery on Postgres", dlq.length === 1 && dlq[0].attempts === 3);
248
+
249
+ // dlq.replay recovers.
250
+ transport.setStatus(200);
251
+ var replay = await wd.dlq.replay(dlq[0].deliveryId);
252
+ check("dlq.replay delivers on Postgres", replay.ok === true);
253
+ var dlqAfter = await wd.dlq.list();
254
+ check("DLQ empty after replay on Postgres", dlqAfter.length === 0);
255
+ } finally {
256
+ try { await driver.close(client); } catch (_e) {}
257
+ try { helpers.teardownVaultOnly(tmpDir); } catch (_e) {}
258
+ _dropTables();
259
+ }
260
+ }
261
+
262
+ module.exports = { run: run };
263
+
264
+ if (require.main === module) {
265
+ run().then(
266
+ function () { console.log("[webhook-dispatcher-pg] OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
267
+ function (e) { console.error("FAIL:", e && e.stack || e); process.exit(1); }
268
+ );
269
+ }
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ /**
3
+ * b.atomicFile.fdSafeReadSync — TOCTOU-safe fd read (CWE-367 /
4
+ * js/file-system-race). The single owner of the open-fd → fstat →
5
+ * read-fully loop that atomic-file / network-tls / vault-seal-pem / backup
6
+ * all route through, with the security guards exposed as opts:
7
+ *
8
+ * - maxBytes — refuse a file larger than the cap (post-fstat)
9
+ * - refuseSymlink — lstat + refuse a symlink source (no follow)
10
+ * - inodeCheck — refuse if the fd inode != the lstat inode (TOCTOU)
11
+ * - expectedHash — SHA3-512 the content must match
12
+ * - encoding — return a decoded string instead of a Buffer
13
+ * - allowShortRead — slice to the bytes read instead of throwing
14
+ * - errorFor — map a failure KIND to the caller's typed error
15
+ */
16
+
17
+ var fs = require("fs");
18
+ var path = require("path");
19
+
20
+ var helpers = require("../helpers");
21
+ var b = helpers.b;
22
+ var check = helpers.check;
23
+
24
+ function _dir() { return b.testing.tempDir("fdsaferead"); }
25
+
26
+ function _throws(fn) {
27
+ try { fn(); return null; } catch (e) { return e; }
28
+ }
29
+
30
+ function testReadsBufferAndString() {
31
+ var dir = _dir();
32
+ try {
33
+ var p = path.join(dir.path, "data.bin");
34
+ var payload = Buffer.from("fd-safe payload ✓", "utf8");
35
+ fs.writeFileSync(p, payload, { mode: 0o600 });
36
+ var buf = b.atomicFile.fdSafeReadSync(p);
37
+ check("fdSafeReadSync: returns a Buffer by default", Buffer.isBuffer(buf) && buf.equals(payload));
38
+ var str = b.atomicFile.fdSafeReadSync(p, { encoding: "utf8" });
39
+ check("fdSafeReadSync: encoding returns a string", str === payload.toString("utf8"));
40
+ } finally { dir.cleanup(); }
41
+ }
42
+
43
+ function testMaxBytesCap() {
44
+ var dir = _dir();
45
+ try {
46
+ var p = path.join(dir.path, "big.bin");
47
+ fs.writeFileSync(p, Buffer.alloc(2048), { mode: 0o600 });
48
+ var e = _throws(function () { b.atomicFile.fdSafeReadSync(p, { maxBytes: 1024 }); });
49
+ check("fdSafeReadSync: maxBytes refuses an over-cap file",
50
+ e !== null && /too-large|maxBytes/i.test(e.code + " " + e.message));
51
+ // Under the cap reads fine.
52
+ var ok = b.atomicFile.fdSafeReadSync(p, { maxBytes: 4096 });
53
+ check("fdSafeReadSync: under the cap reads fine", ok.length === 2048);
54
+ } finally { dir.cleanup(); }
55
+ }
56
+
57
+ function testExpectedHash() {
58
+ var dir = _dir();
59
+ try {
60
+ var p = path.join(dir.path, "hashed.bin");
61
+ fs.writeFileSync(p, Buffer.from("integrity"), { mode: 0o600 });
62
+ var e = _throws(function () {
63
+ b.atomicFile.fdSafeReadSync(p, { expectedHash: "0".repeat(128) });
64
+ });
65
+ check("fdSafeReadSync: wrong expectedHash refuses (integrity)",
66
+ e !== null && /integrity/i.test(e.code + " " + e.message));
67
+ } finally { dir.cleanup(); }
68
+ }
69
+
70
+ function testEnoent() {
71
+ var dir = _dir();
72
+ try {
73
+ var missing = path.join(dir.path, "nope.bin");
74
+ // Default errorFor → AtomicFileError; an errorFor returning undefined
75
+ // rethrows the raw ENOENT (the network-tls / vault / backup posture).
76
+ var eDefault = _throws(function () { b.atomicFile.fdSafeReadSync(missing); });
77
+ check("fdSafeReadSync: missing file (default errorFor) throws a typed atomic-file error",
78
+ eDefault !== null && eDefault.code === "atomic-file/enoent");
79
+ var eRaw = _throws(function () {
80
+ b.atomicFile.fdSafeReadSync(missing, { errorFor: function () { return undefined; } });
81
+ });
82
+ check("fdSafeReadSync: errorFor undefined rethrows raw ENOENT",
83
+ eRaw !== null && eRaw.code === "ENOENT");
84
+ } finally { dir.cleanup(); }
85
+ }
86
+
87
+ function testErrorForCustomError() {
88
+ var dir = _dir();
89
+ try {
90
+ var p = path.join(dir.path, "big2.bin");
91
+ fs.writeFileSync(p, Buffer.alloc(4096), { mode: 0o600 });
92
+ function Tagged(msg) { this.message = msg; this.tag = "custom-too-large"; }
93
+ var e = _throws(function () {
94
+ b.atomicFile.fdSafeReadSync(p, {
95
+ maxBytes: 16,
96
+ errorFor: function (kind) { return kind === "too-large" ? new Tagged("over cap") : undefined; },
97
+ });
98
+ });
99
+ check("fdSafeReadSync: errorFor maps a kind to the caller's typed error",
100
+ e !== null && e.tag === "custom-too-large");
101
+ } finally { dir.cleanup(); }
102
+ }
103
+
104
+ function testRefuseSymlinkAndInodeHappyPath() {
105
+ var dir = _dir();
106
+ try {
107
+ var p = path.join(dir.path, "real.pem");
108
+ fs.writeFileSync(p, Buffer.from("PEM"), { mode: 0o600 });
109
+ // refuseSymlink + inodeCheck on a regular file reads fine (the vault posture).
110
+ var buf = b.atomicFile.fdSafeReadSync(p, { refuseSymlink: true, inodeCheck: true });
111
+ check("fdSafeReadSync: refuseSymlink+inodeCheck reads a regular file", buf.toString() === "PEM");
112
+
113
+ // A symlink source is refused (no follow). Platform-conditional: Windows
114
+ // without SeCreateSymbolicLink can't create symlinks — skip the assertion.
115
+ var victim = path.join(dir.path, "victim.pem");
116
+ fs.writeFileSync(victim, "SECRET", { mode: 0o600 });
117
+ var link = path.join(dir.path, "link.pem");
118
+ var symlinkOk = true;
119
+ try { fs.symlinkSync(victim, link); } catch (_e) { symlinkOk = false; }
120
+ if (symlinkOk) {
121
+ var e = _throws(function () {
122
+ b.atomicFile.fdSafeReadSync(link, {
123
+ refuseSymlink: true,
124
+ errorFor: function (kind) { return kind === "symlink" ? Object.assign(new Error("symlink"), { kind: "symlink" }) : undefined; },
125
+ });
126
+ });
127
+ check("fdSafeReadSync: refuseSymlink refuses a symlink source",
128
+ e !== null && e.kind === "symlink");
129
+ } else {
130
+ check("fdSafeReadSync: symlink case skipped (platform lacks symlink privilege)", true);
131
+ }
132
+ } finally { dir.cleanup(); }
133
+ }
134
+
135
+ async function run() {
136
+ testReadsBufferAndString();
137
+ testMaxBytesCap();
138
+ testExpectedHash();
139
+ testEnoent();
140
+ testErrorForCustomError();
141
+ testRefuseSymlinkAndInodeHappyPath();
142
+ }
143
+
144
+ module.exports = { run: run };
145
+
146
+ if (require.main === module) {
147
+ run().then(function () { console.log("OK"); })
148
+ .catch(function (e) { console.error(e.stack || e); process.exit(1); });
149
+ }
@@ -35,6 +35,11 @@ var LIB_ROOT = path.resolve(__dirname, "..", "..", "lib");
35
35
  // `[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+`.
36
36
  var EMIT_PATTERNS = [
37
37
  /(?:_emit|_emitAudit|_auditEmit|emitAudit)\(\s*["']([a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+)["']/g,
38
+ // audit().namespaced("ns.scope"[, auditFlag]) — the audit namespace lives in
39
+ // the factory call now, not in each safeEmit/_emitAudit invocation. Scoped to
40
+ // `audit().namespaced` so `observability().namespaced` metric prefixes (a
41
+ // separate vocabulary, not FRAMEWORK_NAMESPACES) are NOT pulled in.
42
+ /audit\(\)\.namespaced\(\s*["']([a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+)["']/g,
38
43
  /action\s*:\s*["']([a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+)["']/g,
39
44
  ];
40
45
 
@@ -126,9 +131,55 @@ function testFrameworkNamespacesShape() {
126
131
  }
127
132
  }
128
133
 
134
+ // auditEmit.gatedReasonEmitter — the gated, reason-hoisting emitter shared by
135
+ // backup / restore / scheduler / config-drift / legal-hold.
136
+ function testGatedReasonEmitter() {
137
+ var auditEmit = require("../../lib/audit-emit");
138
+ var audit = require("../../lib/audit");
139
+ var captured = [];
140
+ var realSafe = audit.safeEmit;
141
+ audit.safeEmit = function (e) { captured.push(e); }; // late-bound default sink
142
+ try {
143
+ var emit = auditEmit.gatedReasonEmitter({ audit: true });
144
+ emit("backup.started", { jobId: 7 }, "success");
145
+ emit("backup.failed", { jobId: 7, reason: "disk-full" }, "failure");
146
+ check("gatedReasonEmitter: reason null when info.reason absent",
147
+ captured[0] && captured[0].action === "backup.started" && captured[0].reason === null);
148
+ check("gatedReasonEmitter: reason hoisted from info.reason",
149
+ captured[1] && captured[1].reason === "disk-full" && captured[1].outcome === "failure");
150
+ check("gatedReasonEmitter: metadata is the info object",
151
+ captured[1] && captured[1].metadata && captured[1].metadata.jobId === 7);
152
+
153
+ // gate OFF — drop-silent, no emit
154
+ var n = captured.length;
155
+ auditEmit.gatedReasonEmitter({ audit: false })("x", { reason: "y" }, "success");
156
+ check("gatedReasonEmitter: gate off suppresses emit", captured.length === n);
157
+
158
+ // extra(info) adds top-level fields (legal-hold's resource)
159
+ auditEmit.gatedReasonEmitter({
160
+ audit: true,
161
+ extra: function (info) { return { resource: { kind: "legal-hold", id: info && info.subjectId } }; },
162
+ })("legalhold.placed", { subjectId: "abc", reason: "litigation" }, "success");
163
+ var last = captured[captured.length - 1];
164
+ check("gatedReasonEmitter: extra() merges top-level fields",
165
+ last && last.resource && last.resource.id === "abc" && last.reason === "litigation");
166
+
167
+ // operator sink routing — goes to the supplied sink, not the framework default
168
+ var sinkEvents = [];
169
+ var m = captured.length;
170
+ auditEmit.gatedReasonEmitter({ audit: true, sink: { safeEmit: function (e) { sinkEvents.push(e); } } })
171
+ ("ns.act", { reason: "r" }, "success");
172
+ check("gatedReasonEmitter: routes to the operator sink",
173
+ sinkEvents.length === 1 && sinkEvents[0].reason === "r" && captured.length === m);
174
+ } finally {
175
+ audit.safeEmit = realSafe;
176
+ }
177
+ }
178
+
129
179
  async function run() {
130
180
  testFrameworkNamespacesShape();
131
181
  testEveryEmittedNamespaceIsRegistered();
182
+ testGatedReasonEmitter();
132
183
  }
133
184
 
134
185
  module.exports = { run: run };