@blamejs/blamejs-shop 0.4.55 → 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 (399) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/admin.js +385 -2
  3. package/lib/asset-manifest.json +1 -1
  4. package/lib/vendor/MANIFEST.json +426 -366
  5. package/lib/vendor/blamejs/.github/codeql/codeql-config.yml +25 -0
  6. package/lib/vendor/blamejs/.github/workflows/actions-lint.yml +3 -3
  7. package/lib/vendor/blamejs/.github/workflows/cflite_batch.yml +1 -1
  8. package/lib/vendor/blamejs/.github/workflows/cflite_pr.yml +1 -1
  9. package/lib/vendor/blamejs/.github/workflows/ci.yml +13 -13
  10. package/lib/vendor/blamejs/.github/workflows/codeql.yml +8 -7
  11. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +2 -2
  12. package/lib/vendor/blamejs/.github/workflows/release-container.yml +4 -4
  13. package/lib/vendor/blamejs/.github/workflows/scorecard.yml +1 -1
  14. package/lib/vendor/blamejs/.github/workflows/sha-to-tag-verify.yml +1 -1
  15. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  16. package/lib/vendor/blamejs/api-snapshot.json +1381 -4
  17. package/lib/vendor/blamejs/eslint.config.mjs +1 -0
  18. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +4 -1
  19. package/lib/vendor/blamejs/examples/wiki/lib/symbol-index.js +5 -2
  20. package/lib/vendor/blamejs/examples/wiki/routes/pages.js +4 -1
  21. package/lib/vendor/blamejs/fuzz/guard-text.fuzz.js +20 -0
  22. package/lib/vendor/blamejs/index.js +2 -0
  23. package/lib/vendor/blamejs/lib/a2a-tasks.js +7 -23
  24. package/lib/vendor/blamejs/lib/acme.js +6 -5
  25. package/lib/vendor/blamejs/lib/agent-event-bus.js +5 -4
  26. package/lib/vendor/blamejs/lib/agent-idempotency.js +2 -5
  27. package/lib/vendor/blamejs/lib/agent-orchestrator.js +2 -5
  28. package/lib/vendor/blamejs/lib/agent-saga.js +3 -5
  29. package/lib/vendor/blamejs/lib/agent-tenant.js +2 -5
  30. package/lib/vendor/blamejs/lib/ai-adverse-decision.js +2 -15
  31. package/lib/vendor/blamejs/lib/ai-capability.js +1 -6
  32. package/lib/vendor/blamejs/lib/ai-dp.js +1 -5
  33. package/lib/vendor/blamejs/lib/ai-input.js +2 -2
  34. package/lib/vendor/blamejs/lib/ai-pref.js +3 -8
  35. package/lib/vendor/blamejs/lib/ai-quota.js +3 -14
  36. package/lib/vendor/blamejs/lib/api-key.js +37 -28
  37. package/lib/vendor/blamejs/lib/archive-adapters.js +2 -4
  38. package/lib/vendor/blamejs/lib/archive-entry-policy.js +32 -0
  39. package/lib/vendor/blamejs/lib/archive-read.js +5 -17
  40. package/lib/vendor/blamejs/lib/archive-tar-read.js +5 -16
  41. package/lib/vendor/blamejs/lib/archive.js +2 -10
  42. package/lib/vendor/blamejs/lib/arg-parser.js +7 -6
  43. package/lib/vendor/blamejs/lib/asyncapi-traits.js +2 -6
  44. package/lib/vendor/blamejs/lib/atomic-file.js +108 -31
  45. package/lib/vendor/blamejs/lib/audit-chain.js +133 -53
  46. package/lib/vendor/blamejs/lib/audit-daily-review.js +24 -14
  47. package/lib/vendor/blamejs/lib/audit-emit.js +82 -0
  48. package/lib/vendor/blamejs/lib/audit-sign.js +257 -0
  49. package/lib/vendor/blamejs/lib/audit.js +84 -0
  50. package/lib/vendor/blamejs/lib/auth/access-lock.js +5 -27
  51. package/lib/vendor/blamejs/lib/auth/dpop.js +23 -35
  52. package/lib/vendor/blamejs/lib/auth/fido-mds3.js +9 -15
  53. package/lib/vendor/blamejs/lib/auth/jwt-external.js +26 -8
  54. package/lib/vendor/blamejs/lib/auth/jwt.js +13 -15
  55. package/lib/vendor/blamejs/lib/auth/lockout.js +6 -25
  56. package/lib/vendor/blamejs/lib/auth/oauth.js +67 -45
  57. package/lib/vendor/blamejs/lib/auth/oid4vci.js +55 -32
  58. package/lib/vendor/blamejs/lib/auth/oid4vp.js +3 -2
  59. package/lib/vendor/blamejs/lib/auth/openid-federation.js +6 -6
  60. package/lib/vendor/blamejs/lib/auth/passkey.js +3 -3
  61. package/lib/vendor/blamejs/lib/auth/password.js +7 -1
  62. package/lib/vendor/blamejs/lib/auth/saml.js +37 -27
  63. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-holder.js +2 -14
  64. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc-issuer.js +2 -14
  65. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +1 -1
  66. package/lib/vendor/blamejs/lib/auth/status-list.js +7 -7
  67. package/lib/vendor/blamejs/lib/auth/step-up.js +6 -12
  68. package/lib/vendor/blamejs/lib/auth-bot-challenge.js +6 -37
  69. package/lib/vendor/blamejs/lib/backup/bundle.js +11 -18
  70. package/lib/vendor/blamejs/lib/backup/index.js +14 -47
  71. package/lib/vendor/blamejs/lib/bounded-map.js +112 -1
  72. package/lib/vendor/blamejs/lib/breach-deadline.js +1 -11
  73. package/lib/vendor/blamejs/lib/cache.js +7 -18
  74. package/lib/vendor/blamejs/lib/cbor.js +2 -1
  75. package/lib/vendor/blamejs/lib/cdn-cache-control.js +8 -9
  76. package/lib/vendor/blamejs/lib/cert.js +3 -10
  77. package/lib/vendor/blamejs/lib/chain-writer.js +162 -47
  78. package/lib/vendor/blamejs/lib/cli.js +5 -1
  79. package/lib/vendor/blamejs/lib/client-hints.js +7 -9
  80. package/lib/vendor/blamejs/lib/cloud-events.js +40 -31
  81. package/lib/vendor/blamejs/lib/cluster-storage.js +2 -38
  82. package/lib/vendor/blamejs/lib/cms-codec.js +2 -1
  83. package/lib/vendor/blamejs/lib/codepoint-class.js +67 -1
  84. package/lib/vendor/blamejs/lib/compliance-ai-act-logging.js +1 -6
  85. package/lib/vendor/blamejs/lib/compliance-ai-act-transparency.js +2 -4
  86. package/lib/vendor/blamejs/lib/compliance-eaa.js +1 -11
  87. package/lib/vendor/blamejs/lib/compliance-sanctions-fetcher.js +21 -28
  88. package/lib/vendor/blamejs/lib/compliance-sanctions.js +2 -14
  89. package/lib/vendor/blamejs/lib/compliance.js +2 -9
  90. package/lib/vendor/blamejs/lib/config-drift.js +2 -12
  91. package/lib/vendor/blamejs/lib/content-digest.js +10 -8
  92. package/lib/vendor/blamejs/lib/cookies.js +5 -11
  93. package/lib/vendor/blamejs/lib/cose.js +19 -11
  94. package/lib/vendor/blamejs/lib/cra-report.js +1 -11
  95. package/lib/vendor/blamejs/lib/crypto-field.js +5 -10
  96. package/lib/vendor/blamejs/lib/crypto.js +120 -3
  97. package/lib/vendor/blamejs/lib/csp.js +235 -3
  98. package/lib/vendor/blamejs/lib/daemon.js +42 -41
  99. package/lib/vendor/blamejs/lib/data-act.js +19 -9
  100. package/lib/vendor/blamejs/lib/db-query.js +6 -40
  101. package/lib/vendor/blamejs/lib/db.js +34 -12
  102. package/lib/vendor/blamejs/lib/dbsc.js +5 -6
  103. package/lib/vendor/blamejs/lib/ddl-change-control.js +18 -14
  104. package/lib/vendor/blamejs/lib/deprecate.js +4 -5
  105. package/lib/vendor/blamejs/lib/did.js +6 -2
  106. package/lib/vendor/blamejs/lib/dsr.js +8 -12
  107. package/lib/vendor/blamejs/lib/external-db-migrate.js +21 -22
  108. package/lib/vendor/blamejs/lib/external-db.js +14 -26
  109. package/lib/vendor/blamejs/lib/fda-21cfr11.js +12 -8
  110. package/lib/vendor/blamejs/lib/fdx.js +22 -18
  111. package/lib/vendor/blamejs/lib/file-upload.js +80 -66
  112. package/lib/vendor/blamejs/lib/flag-evaluation-context.js +5 -8
  113. package/lib/vendor/blamejs/lib/framework-error.js +12 -0
  114. package/lib/vendor/blamejs/lib/framework-schema.js +19 -0
  115. package/lib/vendor/blamejs/lib/fsm.js +7 -12
  116. package/lib/vendor/blamejs/lib/gate-contract.js +869 -38
  117. package/lib/vendor/blamejs/lib/gdpr-ropa.js +4 -13
  118. package/lib/vendor/blamejs/lib/graphql-federation.js +1 -1
  119. package/lib/vendor/blamejs/lib/guard-agent-registry.js +2 -1
  120. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  121. package/lib/vendor/blamejs/lib/guard-archive.js +9 -30
  122. package/lib/vendor/blamejs/lib/guard-auth.js +23 -80
  123. package/lib/vendor/blamejs/lib/guard-cidr.js +20 -96
  124. package/lib/vendor/blamejs/lib/guard-csv.js +135 -196
  125. package/lib/vendor/blamejs/lib/guard-domain.js +23 -106
  126. package/lib/vendor/blamejs/lib/guard-dsn.js +16 -13
  127. package/lib/vendor/blamejs/lib/guard-email.js +46 -53
  128. package/lib/vendor/blamejs/lib/guard-envelope.js +1 -1
  129. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +2 -1
  130. package/lib/vendor/blamejs/lib/guard-filename.js +12 -60
  131. package/lib/vendor/blamejs/lib/guard-graphql.js +28 -75
  132. package/lib/vendor/blamejs/lib/guard-html-wcag.js +15 -2
  133. package/lib/vendor/blamejs/lib/guard-html.js +65 -117
  134. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +2 -1
  135. package/lib/vendor/blamejs/lib/guard-image.js +280 -77
  136. package/lib/vendor/blamejs/lib/guard-imap-command.js +8 -9
  137. package/lib/vendor/blamejs/lib/guard-json.js +87 -103
  138. package/lib/vendor/blamejs/lib/guard-jsonpath.js +20 -88
  139. package/lib/vendor/blamejs/lib/guard-jwt.js +32 -114
  140. package/lib/vendor/blamejs/lib/guard-list-id.js +2 -7
  141. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +2 -7
  142. package/lib/vendor/blamejs/lib/guard-mail-compose.js +5 -6
  143. package/lib/vendor/blamejs/lib/guard-mail-move.js +2 -1
  144. package/lib/vendor/blamejs/lib/guard-mail-query.js +5 -3
  145. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +6 -7
  146. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +5 -4
  147. package/lib/vendor/blamejs/lib/guard-markdown.js +76 -110
  148. package/lib/vendor/blamejs/lib/guard-message-id.js +5 -6
  149. package/lib/vendor/blamejs/lib/guard-mime.js +20 -99
  150. package/lib/vendor/blamejs/lib/guard-oauth.js +19 -73
  151. package/lib/vendor/blamejs/lib/guard-pdf.js +65 -72
  152. package/lib/vendor/blamejs/lib/guard-pop3-command.js +12 -13
  153. package/lib/vendor/blamejs/lib/guard-posture-chain.js +2 -1
  154. package/lib/vendor/blamejs/lib/guard-regex.js +24 -99
  155. package/lib/vendor/blamejs/lib/guard-saga-config.js +2 -1
  156. package/lib/vendor/blamejs/lib/guard-shell.js +22 -87
  157. package/lib/vendor/blamejs/lib/guard-smtp-command.js +8 -11
  158. package/lib/vendor/blamejs/lib/guard-sql.js +15 -13
  159. package/lib/vendor/blamejs/lib/guard-stream-args.js +2 -1
  160. package/lib/vendor/blamejs/lib/guard-svg.js +95 -140
  161. package/lib/vendor/blamejs/lib/guard-template.js +23 -80
  162. package/lib/vendor/blamejs/lib/guard-tenant-id.js +2 -1
  163. package/lib/vendor/blamejs/lib/guard-text.js +592 -0
  164. package/lib/vendor/blamejs/lib/guard-time.js +27 -95
  165. package/lib/vendor/blamejs/lib/guard-uuid.js +21 -93
  166. package/lib/vendor/blamejs/lib/guard-xml.js +76 -106
  167. package/lib/vendor/blamejs/lib/guard-yaml.js +24 -60
  168. package/lib/vendor/blamejs/lib/http-client-cache.js +5 -12
  169. package/lib/vendor/blamejs/lib/http-client-cookie-jar.js +2 -4
  170. package/lib/vendor/blamejs/lib/http-client.js +8 -21
  171. package/lib/vendor/blamejs/lib/http-message-signature.js +3 -2
  172. package/lib/vendor/blamejs/lib/i18n-messageformat.js +5 -7
  173. package/lib/vendor/blamejs/lib/i18n.js +83 -26
  174. package/lib/vendor/blamejs/lib/inbox.js +8 -8
  175. package/lib/vendor/blamejs/lib/incident-report.js +3 -21
  176. package/lib/vendor/blamejs/lib/ip-utils.js +49 -6
  177. package/lib/vendor/blamejs/lib/jobs.js +3 -2
  178. package/lib/vendor/blamejs/lib/keychain.js +6 -18
  179. package/lib/vendor/blamejs/lib/legal-hold.js +6 -15
  180. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +44 -112
  181. package/lib/vendor/blamejs/lib/log-stream-otlp-grpc.js +17 -14
  182. package/lib/vendor/blamejs/lib/log-stream-otlp.js +16 -80
  183. package/lib/vendor/blamejs/lib/log-stream-webhook.js +20 -92
  184. package/lib/vendor/blamejs/lib/mail-arc-sign.js +8 -3
  185. package/lib/vendor/blamejs/lib/mail-arf.js +3 -2
  186. package/lib/vendor/blamejs/lib/mail-auth.js +40 -66
  187. package/lib/vendor/blamejs/lib/mail-bimi.js +19 -39
  188. package/lib/vendor/blamejs/lib/mail-crypto-pgp.js +3 -2
  189. package/lib/vendor/blamejs/lib/mail-dav.js +8 -35
  190. package/lib/vendor/blamejs/lib/mail-deploy.js +6 -9
  191. package/lib/vendor/blamejs/lib/mail-dkim.js +19 -38
  192. package/lib/vendor/blamejs/lib/mail-greylist.js +15 -26
  193. package/lib/vendor/blamejs/lib/mail-helo.js +2 -3
  194. package/lib/vendor/blamejs/lib/mail-journal.js +2 -1
  195. package/lib/vendor/blamejs/lib/mail-mdn.js +4 -3
  196. package/lib/vendor/blamejs/lib/mail-rbl.js +5 -8
  197. package/lib/vendor/blamejs/lib/mail-scan.js +2 -2
  198. package/lib/vendor/blamejs/lib/mail-send-deliver.js +33 -20
  199. package/lib/vendor/blamejs/lib/mail-server-imap.js +32 -87
  200. package/lib/vendor/blamejs/lib/mail-server-jmap.js +35 -51
  201. package/lib/vendor/blamejs/lib/mail-server-managesieve.js +29 -83
  202. package/lib/vendor/blamejs/lib/mail-server-mx.js +33 -74
  203. package/lib/vendor/blamejs/lib/mail-server-net.js +177 -0
  204. package/lib/vendor/blamejs/lib/mail-server-pop3.js +30 -83
  205. package/lib/vendor/blamejs/lib/mail-server-rate-limit.js +30 -6
  206. package/lib/vendor/blamejs/lib/mail-server-submission.js +34 -73
  207. package/lib/vendor/blamejs/lib/mail-server-tls.js +89 -0
  208. package/lib/vendor/blamejs/lib/mail-spam-score.js +7 -8
  209. package/lib/vendor/blamejs/lib/mail-store.js +3 -2
  210. package/lib/vendor/blamejs/lib/mail.js +6 -11
  211. package/lib/vendor/blamejs/lib/markup-escape.js +31 -0
  212. package/lib/vendor/blamejs/lib/markup-tokenizer.js +54 -0
  213. package/lib/vendor/blamejs/lib/mcp-tool-registry.js +26 -23
  214. package/lib/vendor/blamejs/lib/mcp.js +1 -1
  215. package/lib/vendor/blamejs/lib/mdoc.js +11 -12
  216. package/lib/vendor/blamejs/lib/metrics.js +32 -30
  217. package/lib/vendor/blamejs/lib/middleware/age-gate.js +3 -23
  218. package/lib/vendor/blamejs/lib/middleware/api-encrypt.js +11 -22
  219. package/lib/vendor/blamejs/lib/middleware/assetlinks.js +2 -7
  220. package/lib/vendor/blamejs/lib/middleware/bearer-auth.js +2 -1
  221. package/lib/vendor/blamejs/lib/middleware/body-parser.js +31 -48
  222. package/lib/vendor/blamejs/lib/middleware/bot-disclose.js +7 -10
  223. package/lib/vendor/blamejs/lib/middleware/bot-guard.js +2 -10
  224. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +13 -2
  225. package/lib/vendor/blamejs/lib/middleware/daily-byte-quota.js +6 -26
  226. package/lib/vendor/blamejs/lib/middleware/deny-response.js +19 -1
  227. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +7 -0
  228. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +4 -20
  229. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +20 -28
  230. package/lib/vendor/blamejs/lib/middleware/scim-server.js +3 -2
  231. package/lib/vendor/blamejs/lib/middleware/security-headers.js +9 -1
  232. package/lib/vendor/blamejs/lib/middleware/security-txt.js +2 -6
  233. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +12 -27
  234. package/lib/vendor/blamejs/lib/middleware/web-app-manifest.js +2 -7
  235. package/lib/vendor/blamejs/lib/migrations.js +4 -13
  236. package/lib/vendor/blamejs/lib/mime-parse.js +34 -17
  237. package/lib/vendor/blamejs/lib/module-loader.js +44 -0
  238. package/lib/vendor/blamejs/lib/money.js +105 -0
  239. package/lib/vendor/blamejs/lib/mtls-ca.js +116 -36
  240. package/lib/vendor/blamejs/lib/network-byte-quota.js +4 -18
  241. package/lib/vendor/blamejs/lib/network-dane.js +8 -6
  242. package/lib/vendor/blamejs/lib/network-dns-resolver.js +97 -6
  243. package/lib/vendor/blamejs/lib/network-dnssec.js +16 -16
  244. package/lib/vendor/blamejs/lib/network-heartbeat.js +3 -2
  245. package/lib/vendor/blamejs/lib/network-smtp-policy.js +29 -41
  246. package/lib/vendor/blamejs/lib/network-tls.js +40 -42
  247. package/lib/vendor/blamejs/lib/nis2-report.js +1 -11
  248. package/lib/vendor/blamejs/lib/nonce-store.js +81 -3
  249. package/lib/vendor/blamejs/lib/numeric-bounds.js +22 -8
  250. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +2 -6
  251. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +5 -45
  252. package/lib/vendor/blamejs/lib/object-store/gcs.js +8 -71
  253. package/lib/vendor/blamejs/lib/object-store/http-put.js +1 -5
  254. package/lib/vendor/blamejs/lib/object-store/http-request.js +128 -0
  255. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +2 -1
  256. package/lib/vendor/blamejs/lib/object-store/sigv4.js +9 -77
  257. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -25
  258. package/lib/vendor/blamejs/lib/observability.js +95 -0
  259. package/lib/vendor/blamejs/lib/openapi-paths-builder.js +7 -3
  260. package/lib/vendor/blamejs/lib/otel-export.js +7 -10
  261. package/lib/vendor/blamejs/lib/outbox.js +43 -37
  262. package/lib/vendor/blamejs/lib/pagination.js +11 -15
  263. package/lib/vendor/blamejs/lib/parsers/safe-env.js +5 -4
  264. package/lib/vendor/blamejs/lib/parsers/safe-ini.js +10 -4
  265. package/lib/vendor/blamejs/lib/parsers/safe-toml.js +11 -9
  266. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +2 -2
  267. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +7 -6
  268. package/lib/vendor/blamejs/lib/pick.js +63 -5
  269. package/lib/vendor/blamejs/lib/pipl-cn.js +69 -59
  270. package/lib/vendor/blamejs/lib/privacy-pass.js +8 -6
  271. package/lib/vendor/blamejs/lib/problem-details.js +2 -5
  272. package/lib/vendor/blamejs/lib/pubsub.js +4 -8
  273. package/lib/vendor/blamejs/lib/redact.js +2 -1
  274. package/lib/vendor/blamejs/lib/render.js +4 -2
  275. package/lib/vendor/blamejs/lib/request-helpers.js +133 -6
  276. package/lib/vendor/blamejs/lib/restore.js +5 -22
  277. package/lib/vendor/blamejs/lib/retention.js +3 -5
  278. package/lib/vendor/blamejs/lib/safe-async.js +457 -0
  279. package/lib/vendor/blamejs/lib/safe-buffer.js +137 -6
  280. package/lib/vendor/blamejs/lib/safe-decompress.js +2 -1
  281. package/lib/vendor/blamejs/lib/safe-dns.js +2 -1
  282. package/lib/vendor/blamejs/lib/safe-ical.js +12 -26
  283. package/lib/vendor/blamejs/lib/safe-json.js +7 -8
  284. package/lib/vendor/blamejs/lib/safe-jsonpath.js +6 -5
  285. package/lib/vendor/blamejs/lib/safe-mime.js +25 -29
  286. package/lib/vendor/blamejs/lib/safe-redirect.js +2 -5
  287. package/lib/vendor/blamejs/lib/safe-schema.js +7 -6
  288. package/lib/vendor/blamejs/lib/safe-sql.js +126 -0
  289. package/lib/vendor/blamejs/lib/safe-vcard.js +12 -26
  290. package/lib/vendor/blamejs/lib/sandbox-worker.js +9 -2
  291. package/lib/vendor/blamejs/lib/sandbox.js +3 -2
  292. package/lib/vendor/blamejs/lib/scheduler.js +5 -12
  293. package/lib/vendor/blamejs/lib/sec-cyber.js +82 -37
  294. package/lib/vendor/blamejs/lib/seeders.js +4 -11
  295. package/lib/vendor/blamejs/lib/self-update.js +92 -69
  296. package/lib/vendor/blamejs/lib/session-device-binding.js +112 -66
  297. package/lib/vendor/blamejs/lib/session.js +194 -6
  298. package/lib/vendor/blamejs/lib/sql.js +225 -78
  299. package/lib/vendor/blamejs/lib/sse.js +6 -10
  300. package/lib/vendor/blamejs/lib/static.js +136 -98
  301. package/lib/vendor/blamejs/lib/storage.js +4 -2
  302. package/lib/vendor/blamejs/lib/structured-fields.js +275 -16
  303. package/lib/vendor/blamejs/lib/tenant-quota.js +2 -20
  304. package/lib/vendor/blamejs/lib/tsa.js +11 -15
  305. package/lib/vendor/blamejs/lib/validate-opts.js +154 -8
  306. package/lib/vendor/blamejs/lib/vault/seal-pem-file.js +30 -48
  307. package/lib/vendor/blamejs/lib/vault-aad.js +3 -2
  308. package/lib/vendor/blamejs/lib/vc.js +2 -7
  309. package/lib/vendor/blamejs/lib/vex.js +35 -13
  310. package/lib/vendor/blamejs/lib/web-push-vapid.js +23 -20
  311. package/lib/vendor/blamejs/lib/webhook-dispatcher.js +706 -0
  312. package/lib/vendor/blamejs/lib/webhook.js +43 -18
  313. package/lib/vendor/blamejs/lib/websocket-channels.js +9 -7
  314. package/lib/vendor/blamejs/lib/websocket.js +7 -3
  315. package/lib/vendor/blamejs/lib/worm.js +2 -3
  316. package/lib/vendor/blamejs/lib/ws-client.js +8 -10
  317. package/lib/vendor/blamejs/package.json +1 -1
  318. package/lib/vendor/blamejs/release-notes/v0.15.13.json +81 -0
  319. package/lib/vendor/blamejs/scripts/check-changelog-extract.js +1 -1
  320. package/lib/vendor/blamejs/test/00-primitives.js +136 -7
  321. package/lib/vendor/blamejs/test/10-state.js +9 -3
  322. package/lib/vendor/blamejs/test/30-chain.js +40 -0
  323. package/lib/vendor/blamejs/test/helpers/check.js +18 -0
  324. package/lib/vendor/blamejs/test/helpers/db.js +4 -0
  325. package/lib/vendor/blamejs/test/helpers/index.js +1 -0
  326. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +2 -1
  327. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +2 -1
  328. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +8 -1
  329. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +1 -1
  330. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +2 -1
  331. package/lib/vendor/blamejs/test/integration/webhook-dispatcher-pg.test.js +269 -0
  332. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-fd-read.test.js +149 -0
  333. package/lib/vendor/blamejs/test/layer-0-primitives/audit-framework-namespaces.test.js +51 -0
  334. package/lib/vendor/blamejs/test/layer-0-primitives/audit-sign-anchor.test.js +88 -0
  335. package/lib/vendor/blamejs/test/layer-0-primitives/audit-use-store.test.js +55 -1
  336. package/lib/vendor/blamejs/test/layer-0-primitives/backup-object-store-adapter.test.js +2 -2
  337. package/lib/vendor/blamejs/test/layer-0-primitives/bot-guard.test.js +1 -1
  338. package/lib/vendor/blamejs/test/layer-0-primitives/bounded-map.test.js +129 -0
  339. package/lib/vendor/blamejs/test/layer-0-primitives/chain-writer-multichain.test.js +107 -0
  340. package/lib/vendor/blamejs/test/layer-0-primitives/cli-api-key.test.js +12 -0
  341. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +2788 -3214
  342. package/lib/vendor/blamejs/test/layer-0-primitives/codepoint-class.test.js +78 -0
  343. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-base64url.test.js +63 -0
  344. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-hash-stream.test.js +2 -1
  345. package/lib/vendor/blamejs/test/layer-0-primitives/csp-builder.test.js +50 -0
  346. package/lib/vendor/blamejs/test/layer-0-primitives/csp-nonce.test.js +1 -1
  347. package/lib/vendor/blamejs/test/layer-0-primitives/daemon.test.js +2 -1
  348. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-resolve-opts.test.js +76 -0
  349. package/lib/vendor/blamejs/test/layer-0-primitives/flag.test.js +9 -0
  350. package/lib/vendor/blamejs/test/layer-0-primitives/gate-contract-content-gate.test.js +290 -0
  351. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +84 -0
  352. package/lib/vendor/blamejs/test/layer-0-primitives/guard-email.test.js +78 -0
  353. package/lib/vendor/blamejs/test/layer-0-primitives/guard-filename.test.js +23 -0
  354. package/lib/vendor/blamejs/test/layer-0-primitives/guard-gate-disposition-coverage.test.js +93 -0
  355. package/lib/vendor/blamejs/test/layer-0-primitives/guard-html.test.js +60 -0
  356. package/lib/vendor/blamejs/test/layer-0-primitives/guard-image.test.js +184 -0
  357. package/lib/vendor/blamejs/test/layer-0-primitives/guard-imap-command.test.js +0 -0
  358. package/lib/vendor/blamejs/test/layer-0-primitives/guard-json.test.js +54 -0
  359. package/lib/vendor/blamejs/test/layer-0-primitives/guard-managesieve-command.test.js +10 -0
  360. package/lib/vendor/blamejs/test/layer-0-primitives/guard-markdown.test.js +45 -0
  361. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pdf.test.js +101 -0
  362. package/lib/vendor/blamejs/test/layer-0-primitives/guard-pop3-command.test.js +18 -0
  363. package/lib/vendor/blamejs/test/layer-0-primitives/guard-svg.test.js +76 -0
  364. package/lib/vendor/blamejs/test/layer-0-primitives/guard-text.test.js +365 -0
  365. package/lib/vendor/blamejs/test/layer-0-primitives/guard-xml.test.js +35 -0
  366. package/lib/vendor/blamejs/test/layer-0-primitives/guard-yaml.test.js +36 -0
  367. package/lib/vendor/blamejs/test/layer-0-primitives/i18n.test.js +20 -0
  368. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -0
  369. package/lib/vendor/blamejs/test/layer-0-primitives/ip-utils.test.js +83 -0
  370. package/lib/vendor/blamejs/test/layer-0-primitives/mail-arf.test.js +10 -0
  371. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +39 -0
  372. package/lib/vendor/blamejs/test/layer-0-primitives/mail-dkim.test.js +36 -0
  373. package/lib/vendor/blamejs/test/layer-0-primitives/mail-greylist.test.js +17 -0
  374. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-tls.test.js +39 -0
  375. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +17 -0
  376. package/lib/vendor/blamejs/test/layer-0-primitives/mime-parse.test.js +106 -0
  377. package/lib/vendor/blamejs/test/layer-0-primitives/money.test.js +17 -0
  378. package/lib/vendor/blamejs/test/layer-0-primitives/mtls-ca-revocation.test.js +98 -0
  379. package/lib/vendor/blamejs/test/layer-0-primitives/nonce-store-release.test.js +77 -0
  380. package/lib/vendor/blamejs/test/layer-0-primitives/observability.test.js +48 -0
  381. package/lib/vendor/blamejs/test/layer-0-primitives/rate-limit-memory-getorinsert.test.js +100 -0
  382. package/lib/vendor/blamejs/test/layer-0-primitives/request-helpers.test.js +88 -0
  383. package/lib/vendor/blamejs/test/layer-0-primitives/safe-async-loops.test.js +278 -0
  384. package/lib/vendor/blamejs/test/layer-0-primitives/safe-buffer-linear-scans.test.js +37 -0
  385. package/lib/vendor/blamejs/test/layer-0-primitives/safe-jsonpath.test.js +14 -0
  386. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +19 -0
  387. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +1 -1
  388. package/lib/vendor/blamejs/test/layer-0-primitives/self-update.test.js +2 -1
  389. package/lib/vendor/blamejs/test/layer-0-primitives/session-device-binding.test.js +18 -0
  390. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +1 -1
  391. package/lib/vendor/blamejs/test/layer-0-primitives/session-valid-from.test.js +73 -0
  392. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +100 -0
  393. package/lib/vendor/blamejs/test/layer-0-primitives/structured-fields.test.js +80 -0
  394. package/lib/vendor/blamejs/test/layer-0-primitives/validate-opts-shape.test.js +235 -0
  395. package/lib/vendor/blamejs/test/layer-0-primitives/webhook-dispatcher.test.js +374 -0
  396. package/lib/vendor/blamejs/test/layer-0-primitives/webhook.test.js +75 -8
  397. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +3 -3
  398. package/lib/winback-campaigns.js +202 -42
  399. package/package.json +1 -1
@@ -50,6 +50,8 @@ var bCrypto = require("./crypto");
50
50
  var lazyRequire = require("./lazy-require");
51
51
  var safeAsync = require("./safe-async");
52
52
  var validateOpts = require("./validate-opts");
53
+ var numericBounds = require("./numeric-bounds");
54
+ var codepointClass = require("./codepoint-class");
53
55
  var { GateContractError, defineClass } = require("./framework-error");
54
56
 
55
57
  var observability = lazyRequire(function () { return require("./observability"); });
@@ -977,10 +979,8 @@ function canaryGate(gate, opts) {
977
979
  function cachingGate(gate, opts) {
978
980
  opts = opts || {};
979
981
  var backend = opts.backend;
980
- if (!backend || typeof backend.get !== "function" || typeof backend.set !== "function") {
981
- throw _err("gate-contract/bad-opt",
982
- "cachingGate: opts.backend must expose { get, set } (b.cache shape)");
983
- }
982
+ validateOpts.requireMethods(backend, ["get", "set"],
983
+ "cachingGate: opts.backend (b.cache shape)", GateContractError, "gate-contract/bad-opt");
984
984
  // ttlMs is read inside check() via closure; keep DEFAULT_CACHE_TTL_MS
985
985
  // referenced even if the host-side cache wrapping path doesn't need
986
986
  // explicit TTL today (the gate's per-instance cache uses cacheTtlMs).
@@ -1166,6 +1166,44 @@ function makeProfileResolver(cfg) {
1166
1166
  };
1167
1167
  }
1168
1168
 
1169
+ /**
1170
+ * @primitive b.gateContract.resolveProfileName
1171
+ * @signature b.gateContract.resolveProfileName(opts, postures, defaultProfile)
1172
+ * @since 0.15.13
1173
+ * @status stable
1174
+ * @related b.gateContract.makeProfileResolver
1175
+ *
1176
+ * Resolve a profile NAME from create-time opts with PROFILE precedence: an
1177
+ * explicit `opts.profile` wins, else `opts.posture` mapped through the
1178
+ * compliance-posture table, else `defaultProfile`. Returns the name WITHOUT
1179
+ * validating it — the caller checks membership in its own `PROFILES` map and
1180
+ * throws its own typed, field-specific error. This is the resolution EXPRESSION
1181
+ * the mail-scanner / envelope factories (mail-greylist / mail-rbl / mail-scan /
1182
+ * mail-spam-score / mail-helo / guard-envelope) each hand-rolled identically.
1183
+ *
1184
+ * It differs from `makeProfileResolver` in two deliberate ways: it does not
1185
+ * throw (so the caller keeps its bespoke bad-profile message) and it gives
1186
+ * `profile` precedence rather than `posture` precedence. The two precedences
1187
+ * coexist in the framework today (the `defineParser`-shaped guards resolve
1188
+ * posture-first); unifying them is a policy decision, and routing every caller
1189
+ * through one of these two helpers is what makes that decision a single edit.
1190
+ *
1191
+ * @opts
1192
+ * profile: string, // explicit profile name — wins when present
1193
+ * posture: string, // compliance posture, mapped through `postures`
1194
+ *
1195
+ * @example
1196
+ * var name = b.gateContract.resolveProfileName(
1197
+ * { profile: "balanced" }, COMPLIANCE_POSTURES, "strict");
1198
+ * // → "balanced"
1199
+ */
1200
+ function resolveProfileName(opts, postures, defaultProfile) {
1201
+ opts = opts || {};
1202
+ return opts.profile ||
1203
+ (opts.posture && postures && postures[opts.posture]) ||
1204
+ defaultProfile;
1205
+ }
1206
+
1169
1207
  /**
1170
1208
  * @primitive b.gateContract.throwOnRefusalSeverity
1171
1209
  * @signature b.gateContract.throwOnRefusalSeverity(issues, cfg)
@@ -1249,6 +1287,244 @@ var ALL_STRICT_POSTURES = Object.freeze({
1249
1287
  soc2: "strict",
1250
1288
  });
1251
1289
 
1290
+ /**
1291
+ * @primitive b.gateContract.CHAR_THREATS_REJECT_ALL
1292
+ * @signature b.gateContract.CHAR_THREATS_REJECT_ALL
1293
+ * @since 0.15.13
1294
+ * @status stable
1295
+ * @compliance hipaa, pci-dss, gdpr, soc2
1296
+ * @related b.gateContract.charThreatDisposition, b.gateContract.makeProfileBuilder
1297
+ *
1298
+ * The universal character-safety floor: the four invisible-character
1299
+ * threats — BIDI overrides, C0/C1 control bytes, embedded null bytes,
1300
+ * and zero-width characters — each set to `"reject"`. These four
1301
+ * classes are categorically unsafe in an identifier or structured
1302
+ * value (forgery, log injection, label-segmentation, parser
1303
+ * confusion), so every identifier/protocol guard refuses them in
1304
+ * every profile tier and the content guards refuse them in `strict`.
1305
+ *
1306
+ * Spread this frozen block into a profile tier instead of re-declaring
1307
+ * the four lines: `{ ...gateContract.CHAR_THREATS_REJECT_ALL, ... }`.
1308
+ * A tier that relaxes one class overrides after the spread (e.g.
1309
+ * `{ ...CHAR_THREATS_REJECT_ALL, zeroWidthPolicy: "strip" }`), keeping
1310
+ * the floor for the other three. Frozen and shared by reference; the
1311
+ * spread copies the values into each consumer's own tier object.
1312
+ *
1313
+ * @example
1314
+ * var PROFILES = Object.freeze({
1315
+ * strict: { ...b.gateContract.CHAR_THREATS_REJECT_ALL, maxBytes: 256 },
1316
+ * });
1317
+ * PROFILES.strict.bidiPolicy; // → "reject"
1318
+ * Object.isFrozen(b.gateContract.CHAR_THREATS_REJECT_ALL); // → true
1319
+ */
1320
+ var CHAR_THREATS_REJECT_ALL = Object.freeze({
1321
+ bidiPolicy: "reject",
1322
+ controlPolicy: "reject",
1323
+ nullBytePolicy: "reject",
1324
+ zeroWidthPolicy: "reject",
1325
+ });
1326
+
1327
+ /**
1328
+ * @primitive b.gateContract.DANGEROUS_URL_SCHEMES
1329
+ * @signature b.gateContract.DANGEROUS_URL_SCHEMES
1330
+ * @since 0.15.13
1331
+ * @status stable
1332
+ * @compliance soc2
1333
+ * @related b.gateContract.CHAR_THREATS_REJECT_ALL, b.guardHtml.validate, b.guardSvg.validate
1334
+ *
1335
+ * The frozen denylist of URL schemes that are categorically unsafe inside a
1336
+ * markup attribute value (`href` / `src` / `xlink:href`) — the markup XSS and
1337
+ * dangerous-resource vector set. `javascript` / `vbscript` / `livescript` /
1338
+ * `mocha` / `ecmascript` execute script; `data` / `view-source` / `mhtml` /
1339
+ * `feed` carry or expose renderable content; `file` / `jar` / `intent` reach
1340
+ * local resources or protocol handlers. A markup sanitizer rejects an
1341
+ * attribute whose scheme is in this list.
1342
+ *
1343
+ * Lower-cased, scheme-name only (no trailing colon) so callers compare against
1344
+ * a lower-cased parsed scheme via `indexOf(scheme) !== -1`. This is the
1345
+ * markup-attribute DENYLIST — distinct from `b.safeUrl`'s protocol ALLOWLIST,
1346
+ * which governs full-URL parsing where only an explicit set of protocols is
1347
+ * permitted.
1348
+ *
1349
+ * @example
1350
+ * b.gateContract.DANGEROUS_URL_SCHEMES.indexOf("javascript"); // → 0 (dangerous)
1351
+ * b.gateContract.DANGEROUS_URL_SCHEMES.indexOf("https"); // → -1 (allowed)
1352
+ * Object.isFrozen(b.gateContract.DANGEROUS_URL_SCHEMES); // → true
1353
+ */
1354
+ var DANGEROUS_URL_SCHEMES = Object.freeze([
1355
+ "javascript", "vbscript", "livescript", "mocha", "ecmascript",
1356
+ "file", "mhtml", "jar", "intent", "view-source", "feed", "data",
1357
+ ]);
1358
+
1359
+ /**
1360
+ * @primitive b.gateContract.SAFE_URL_SCHEMES
1361
+ * @signature b.gateContract.SAFE_URL_SCHEMES
1362
+ * @since 0.15.13
1363
+ * @status stable
1364
+ * @compliance soc2
1365
+ * @related b.gateContract.DANGEROUS_URL_SCHEMES
1366
+ *
1367
+ * The frozen base allowlist of URL schemes a markup sanitizer accepts in an
1368
+ * attribute value at the `strict` tier — `http` / `https` / `mailto` / `tel`.
1369
+ * A guard extends it for looser tiers (e.g. `SAFE_URL_SCHEMES.concat(["ftp"])`)
1370
+ * rather than re-declaring the base. Scheme names only, no trailing colon.
1371
+ *
1372
+ * @example
1373
+ * b.gateContract.SAFE_URL_SCHEMES; // → ["http","https","mailto","tel"]
1374
+ * Object.isFrozen(b.gateContract.SAFE_URL_SCHEMES); // → true
1375
+ */
1376
+ var SAFE_URL_SCHEMES = Object.freeze(["http", "https", "mailto", "tel"]);
1377
+
1378
+ /**
1379
+ * @primitive b.gateContract.identifierFixtures
1380
+ * @signature b.gateContract.identifierFixtures(benign, hostile, encoding?)
1381
+ * @since 0.15.13
1382
+ * @status stable
1383
+ * @related b.gateContract.defineGuard
1384
+ *
1385
+ * Build an identifier guard's frozen `INTEGRATION_FIXTURES` from one benign
1386
+ * and one hostile sample string. The layer-5 host harness feeds the string
1387
+ * form to `gate.check({ identifier })` and the byte form to the upload /
1388
+ * digest paths, so the two are the same value in two representations. A guard
1389
+ * that hand-writes both forms repeats its sample literal twice (`benignBytes:
1390
+ * Buffer.from("x"), benignIdentifier: "x"`); declaring the string once and
1391
+ * deriving the buffer removes that per-guard duplication. `encoding` defaults
1392
+ * to `"utf8"` — pass `"ascii"` for line-protocol command samples whose bytes
1393
+ * must stay single-octet.
1394
+ *
1395
+ * @example
1396
+ * var INTEGRATION_FIXTURES =
1397
+ * b.gateContract.identifierFixtures("example.com", "192.168.1.1");
1398
+ * INTEGRATION_FIXTURES.benignIdentifier; // → "example.com"
1399
+ * INTEGRATION_FIXTURES.benignBytes; // → Buffer "example.com"
1400
+ * Object.isFrozen(INTEGRATION_FIXTURES); // → true
1401
+ */
1402
+ function identifierFixtures(benign, hostile, encoding) {
1403
+ validateOpts.requireNonEmptyString(benign,
1404
+ "gateContract.identifierFixtures: benign", GateContractError, "gate-contract/bad-opt");
1405
+ validateOpts.requireNonEmptyString(hostile,
1406
+ "gateContract.identifierFixtures: hostile", GateContractError, "gate-contract/bad-opt");
1407
+ var enc = encoding || "utf8";
1408
+ if (typeof enc !== "string" || !Buffer.isEncoding(enc)) {
1409
+ throw _err("gate-contract/bad-opt",
1410
+ "gateContract.identifierFixtures: encoding must be a valid Buffer encoding, got " +
1411
+ JSON.stringify(encoding));
1412
+ }
1413
+ return Object.freeze({
1414
+ kind: "identifier",
1415
+ benignBytes: Buffer.from(benign, enc),
1416
+ hostileBytes: Buffer.from(hostile, enc),
1417
+ benignIdentifier: benign,
1418
+ hostileIdentifier: hostile,
1419
+ });
1420
+ }
1421
+
1422
+ /**
1423
+ * @primitive b.gateContract.compliancePostures
1424
+ * @signature b.gateContract.compliancePostures(profiles, spec)
1425
+ * @since 0.15.13
1426
+ * @status stable
1427
+ * @compliance hipaa, pci-dss, gdpr, soc2
1428
+ * @related b.gateContract.ALL_STRICT_POSTURES, b.gateContract.resolveProfileAndPosture
1429
+ *
1430
+ * Build a content guard's four-posture `COMPLIANCE_POSTURES` map from its
1431
+ * profile set and a single forensic-snippet budget, encoding the framework's
1432
+ * regulation-disposition policy in one place instead of re-declaring it in
1433
+ * every guard. Each regulation maps to the profile tier whose disposition
1434
+ * matches its intent:
1435
+ *
1436
+ * - `hipaa` / `pci-dss` / `soc2` → the `strict` profile. These regimes
1437
+ * demand forensic integrity — the record must not be silently
1438
+ * altered — so every threat class is rejected, never sanitized.
1439
+ * - `gdpr` → the `balanced` profile. Data-minimization favors removing
1440
+ * the offending bytes over rejecting the whole value, so on free-text
1441
+ * content the balanced tier strips the sanitizable character classes (bidi
1442
+ * / control / zero-width) while still rejecting structural threats. For an
1443
+ * identifier guard the balanced tier rejects those classes too —
1444
+ * stripping bytes from an identifier would change its identity — so
1445
+ * the disposition follows the guard's own content kind automatically.
1446
+ *
1447
+ * The forensic snippet budget scales with each regime's retention posture:
1448
+ * `hipaa` / `pci-dss` keep `base` bytes, `gdpr` keeps `base / 2` (retain less
1449
+ * hostile data under data-minimization), `soc2` keeps `base * 2` (audit
1450
+ * retention). Pass `spec.overlays` to layer a deliberate per-posture delta on
1451
+ * top of the tier — e.g. a filename guard stripping bidi / control under
1452
+ * `gdpr` where its balanced profile would reject them. Each returned posture is
1453
+ * frozen and shared by reference.
1454
+ *
1455
+ * @opts
1456
+ * {
1457
+ * base: number, // required, positive even byte count: the hipaa/pci snippet budget
1458
+ * overlays: { // optional per-posture policy deltas, merged last
1459
+ * hipaa: object,
1460
+ * "pci-dss": object,
1461
+ * gdpr: object,
1462
+ * soc2: object,
1463
+ * },
1464
+ * }
1465
+ *
1466
+ * @example
1467
+ * var COMPLIANCE_POSTURES = b.gateContract.compliancePostures(PROFILES, {
1468
+ * base: 256,
1469
+ * });
1470
+ * COMPLIANCE_POSTURES.gdpr.forensicSnippetBytes; // → 128
1471
+ * Object.isFrozen(COMPLIANCE_POSTURES.hipaa); // → true
1472
+ */
1473
+ function compliancePostures(profiles, spec) {
1474
+ validateOpts.requireObject(profiles, "gateContract.compliancePostures", GateContractError);
1475
+ if (!profiles.strict || !profiles.balanced) {
1476
+ throw _err("gate-contract/bad-profiles",
1477
+ "compliancePostures: profiles must include 'strict' and 'balanced'");
1478
+ }
1479
+ spec = spec || {};
1480
+ var base = spec.base;
1481
+ if (typeof base !== "number" || !isFinite(base) || base <= 0 || base % 2 !== 0) {
1482
+ throw _err("gate-contract/bad-base",
1483
+ "compliancePostures: spec.base must be a positive even byte count");
1484
+ }
1485
+ var overlays = spec.overlays || {};
1486
+ function build(tier, snippetBytes, overlay) {
1487
+ return Object.freeze(Object.assign({}, profiles[tier],
1488
+ { forensicSnippetBytes: C.BYTES.bytes(snippetBytes) }, overlay || {}));
1489
+ }
1490
+ return Object.freeze({
1491
+ hipaa: build("strict", base, overlays.hipaa),
1492
+ "pci-dss": build("strict", base, overlays["pci-dss"]),
1493
+ gdpr: build("balanced", base / 2, overlays.gdpr),
1494
+ soc2: build("strict", base * 2, overlays.soc2),
1495
+ });
1496
+ }
1497
+
1498
+ /**
1499
+ * @primitive b.gateContract.strictDefaults
1500
+ * @signature b.gateContract.strictDefaults(profiles, overlay?)
1501
+ * @since 0.15.13
1502
+ * @status stable
1503
+ * @related b.gateContract.compliancePostures, b.gateContract.defineGuard
1504
+ *
1505
+ * Build a guard's frozen `DEFAULTS` opts: its `strict` profile, in `enforce`
1506
+ * mode, plus any per-guard overlay. Every guard's no-opts call path starts from
1507
+ * the strictest profile with enforcement on (security-on by default); the only
1508
+ * variation is a guard that adds a parse runtime cap (`maxRuntimeMs`) or another
1509
+ * default override. Replaces the hand-rolled `Object.freeze(Object.assign({},
1510
+ * PROFILES["strict"], { mode: "enforce", … }))` every guard repeated.
1511
+ *
1512
+ * @opts
1513
+ * overlay: object // optional per-guard default overrides merged last (e.g. { maxRuntimeMs: C.TIME.seconds(10) }); may override `mode`
1514
+ *
1515
+ * @example
1516
+ * var DEFAULTS = b.gateContract.strictDefaults(PROFILES); // strict + enforce
1517
+ * var DEFAULTS = b.gateContract.strictDefaults(PROFILES, { maxRuntimeMs: 10000 }); // + a parse runtime cap
1518
+ */
1519
+ function strictDefaults(profiles, overlay) {
1520
+ validateOpts.requireObject(profiles, "gateContract.strictDefaults", GateContractError);
1521
+ if (!profiles.strict) {
1522
+ throw _err("gate-contract/bad-profiles",
1523
+ "strictDefaults: profiles must include 'strict'");
1524
+ }
1525
+ return Object.freeze(Object.assign({}, profiles.strict, { mode: "enforce" }, overlay || {}));
1526
+ }
1527
+
1252
1528
  /**
1253
1529
  * @primitive b.gateContract.makeRulePackLoader
1254
1530
  * @signature b.gateContract.makeRulePackLoader(errorClass, codePrefix)
@@ -1386,6 +1662,234 @@ function buildGuardGate(name, opts, check) {
1386
1662
  });
1387
1663
  }
1388
1664
 
1665
+ /**
1666
+ * @primitive b.gateContract.severityDisposition
1667
+ * @signature b.gateContract.severityDisposition(issues)
1668
+ * @since 0.15.13
1669
+ * @status stable
1670
+ * @related b.gateContract.buildGuardGate, b.gateContract.buildContentGate
1671
+ *
1672
+ * The non-sanitizing guard gate's severity action-chain in one place. A guard
1673
+ * that cannot repair its subject (an auth bundle, an OAuth flow, a GraphQL
1674
+ * request, image / PDF metadata, an archive entry list, an email body, a regex
1675
+ * pattern) ends its `gate` check with the identical disposition: `serve` when
1676
+ * there are no findings, `audit-only` when no finding reaches refusal severity,
1677
+ * else `refuse`. This is the sibling of `buildContentGate` (which adds the
1678
+ * sanitize attempt for content that CAN be repaired). Each guard keeps its own
1679
+ * subject extraction + validate call, then returns `severityDisposition(rv.issues)`.
1680
+ *
1681
+ * A finding of `critical` OR `high` severity refuses; anything lower is
1682
+ * `audit-only`. The returned shape matches a gate `check` result:
1683
+ * `{ ok, action }` (no `issues` on a clean serve) or `{ ok, action, issues }`.
1684
+ *
1685
+ * @example
1686
+ * var rv = module.exports.validate(bundle, opts);
1687
+ * return b.gateContract.severityDisposition(rv.issues);
1688
+ * // [] → { ok: true, action: "serve" }
1689
+ * // [{ severity: "low" }] → { ok: true, action: "audit-only", issues: [...] }
1690
+ * // [{ severity: "high" }] → { ok: false, action: "refuse", issues: [...] }
1691
+ */
1692
+ function severityDisposition(issues) {
1693
+ if (issues.length === 0) return { ok: true, action: "serve" };
1694
+ var hasCritical = issues.some(function (i) { return i.severity === "critical"; });
1695
+ var hasHigh = issues.some(function (i) { return i.severity === "high"; });
1696
+ if (!hasCritical && !hasHigh) {
1697
+ return { ok: true, action: "audit-only", issues: issues };
1698
+ }
1699
+ return { ok: false, action: "refuse", issues: issues };
1700
+ }
1701
+
1702
+ /**
1703
+ * @primitive b.gateContract.buildContentGate
1704
+ * @signature b.gateContract.buildContentGate(spec)
1705
+ * @since 0.15.13
1706
+ * @status stable
1707
+ * @related b.gateContract.buildGuardGate, b.gateContract.defineGuard
1708
+ *
1709
+ * The content-guard gate action-chain in one place. Every content guard's
1710
+ * `gate(opts)` ran the identical chain — extract the bytes, `serve` a clean
1711
+ * input, `audit-only` when no issue reaches the refusal severity, attempt
1712
+ * `sanitize` when the input is eligible, else `refuse` — differing only in
1713
+ * declarative axes. Passing those axes to one primitive replaces ~30 lines of
1714
+ * per-guard gate body and makes the chain impossible to drift between guards.
1715
+ *
1716
+ * A CRITICAL finding always `refuse`s — too severe to serve even sanitized (a
1717
+ * stripped script can still carry an mXSS / parser-differential vector). Only
1718
+ * HIGH findings are sanitize-eligible, and even then the action is PROVEN, not
1719
+ * guessed: the gate runs `produceSanitized` then RE-VALIDATES its output,
1720
+ * returning `sanitize` only when the result is verifiably clean — otherwise
1721
+ * `refuse`. An operator's `reject` choice lands as critical (→ refuse) and a
1722
+ * `strip` choice as high (→ sanitize-if-verified), so the severity carries the
1723
+ * disposition with no per-policy bookkeeping — replacing a global "is any
1724
+ * policy set to reject?" guess that wrongly froze sanitize for findings
1725
+ * unrelated to the rejected policy. The sanitizer's own policy-respecting
1726
+ * behaviour does the rest: it throws on / leaves a reject-class finding so the
1727
+ * re-validate still refuses, and refuses anything it cannot actually repair.
1728
+ * `sanitizeBlockingKinds` skips the attempt for inputs a text sanitizer must not
1729
+ * touch (gzipped SVGZ bytes); a thrown producer falls through to `refuse`.
1730
+ *
1731
+ * @opts
1732
+ * name: string, // gate label (audit/metric/cache identity)
1733
+ * opts: object, // already resolved profile/posture opts
1734
+ * validate: function, // (subject, opts) -> { ok, issues }
1735
+ * produceSanitized: function, // (subject, opts) -> Buffer|string
1736
+ * ctxField: "text"|"bytes", // default "text" (extractBytesAsText); "bytes" reads ctx.bytes raw
1737
+ * sanitizeBlockingKinds: string[], // issue kinds that skip the sanitize attempt (e.g. ["svgz-compressed"])
1738
+ *
1739
+ * @example
1740
+ * var g = b.gateContract.buildContentGate({
1741
+ * name: "guardXml:strict", opts: resolved, validate: validate,
1742
+ * produceSanitized: function (t, o) { return sanitize(t, o); },
1743
+ * });
1744
+ * (await g.check({ bytes: Buffer.from("<a>1</a>") })).action; // → "serve"
1745
+ */
1746
+ function buildContentGate(spec) {
1747
+ var opts = spec.opts || {};
1748
+ var ctxField = spec.ctxField === "bytes" ? "bytes" : "text";
1749
+ var blockKind = Array.isArray(spec.sanitizeBlockingKinds) ? spec.sanitizeBlockingKinds : [];
1750
+
1751
+ // A finding's disposition is what the operator's POLICY for that finding
1752
+ // class chose, not the finding's impact severity. The guard declares the
1753
+ // binding via spec.dispositionFor(issue, opts); anything it doesn't classify
1754
+ // (an operator-injected rule, a structural hard-cap, an un-mapped kind) falls
1755
+ // back to severity — and that fallback is CONSERVATIVE (a refusal-severity
1756
+ // finding refuses, because the gate has no proof it can be repaired).
1757
+ function _disposition(issue, fromGuard) {
1758
+ if (fromGuard && typeof spec.dispositionFor === "function") {
1759
+ var d = spec.dispositionFor(issue, opts);
1760
+ if (d === "refuse" || d === "sanitize" || d === "audit") return d;
1761
+ }
1762
+ if (issue.disposition === "refuse" || issue.disposition === "sanitize" ||
1763
+ issue.disposition === "audit") return issue.disposition;
1764
+ return (issue.severity === "critical" || issue.severity === "high") ? "refuse" : "audit";
1765
+ }
1766
+
1767
+ return buildGuardGate(spec.name, opts, async function (ctx) {
1768
+ var subject = ctxField === "bytes" ? (ctx && ctx.bytes) : extractBytesAsText(ctx);
1769
+ if (!subject) return { ok: true, action: "serve" };
1770
+
1771
+ var rv = spec.validate(subject, opts);
1772
+ var entries = rv.issues.map(function (i) { return { issue: i, disp: _disposition(i, true) }; });
1773
+ // Operator-injected detect-only findings (spec.extraIssues): the guard owns
1774
+ // no sanitizer for them, so a refusal-severity hit can only refuse — never
1775
+ // serve a "sanitized" output that still carries the operator's finding.
1776
+ if (typeof spec.extraIssues === "function") {
1777
+ var extra = spec.extraIssues(subject, opts, ctx) || [];
1778
+ for (var k = 0; k < extra.length; k++) {
1779
+ entries.push({ issue: extra[k], disp: _disposition(extra[k], false) });
1780
+ }
1781
+ }
1782
+ if (entries.length === 0) return { ok: true, action: "serve" };
1783
+
1784
+ var issues = entries.map(function (e) { return e.issue; });
1785
+ // refuse wins over sanitize wins over audit. A finding whose policy is
1786
+ // `reject` (→ refuse), an always-dangerous denylist hit, or a structural
1787
+ // hard-cap refuses the whole input regardless of any sanitizable siblings.
1788
+ if (entries.some(function (e) { return e.disp === "refuse"; })) {
1789
+ return { ok: false, action: "refuse", issues: issues };
1790
+ }
1791
+ // Some finding's policy chose to mitigate (strip / prefix / redact / drop):
1792
+ // run the guard's own sanitizer, which performs exactly the policy-selected
1793
+ // transform, and serve its output. The operator picked sanitize-and-serve
1794
+ // over reject for these classes, so the result is trusted — no re-validation
1795
+ // (a mitigation like CSV's prefix-tab is in-place, not removal, so a second
1796
+ // detector pass would wrongly refuse it). sanitizeBlockingKinds skips the
1797
+ // attempt for inputs a text sanitizer must not touch (gzipped SVGZ bytes);
1798
+ // a sanitizer that throws (e.g. a reject-policy parse) falls through.
1799
+ if (entries.some(function (e) { return e.disp === "sanitize"; })) {
1800
+ var blocked = blockKind.some(function (kind) {
1801
+ return issues.some(function (it) { return it.kind === kind; });
1802
+ });
1803
+ if (!blocked && typeof spec.produceSanitized === "function") {
1804
+ try {
1805
+ var clean = spec.produceSanitized(subject, opts);
1806
+ var cleanBuf = Buffer.isBuffer(clean) ? clean : Buffer.from(String(clean), "utf8");
1807
+ return { ok: true, action: "sanitize", sanitized: cleanBuf, issues: issues };
1808
+ } catch (_e) { /* sanitizer could not repair → refuse */ }
1809
+ }
1810
+ return { ok: false, action: "refuse", issues: issues };
1811
+ }
1812
+ // Only audit-disposition (sub-refusal observational) findings remain.
1813
+ return { ok: true, action: "audit-only", issues: issues };
1814
+ });
1815
+ }
1816
+
1817
+ /**
1818
+ * @primitive b.gateContract.policyDisposition
1819
+ * @signature b.gateContract.policyDisposition(policy)
1820
+ * @since 0.15.13
1821
+ * @status stable
1822
+ * @related b.gateContract.buildContentGate
1823
+ *
1824
+ * Map an operator content-policy value to the gate disposition it selects.
1825
+ * A content guard emits a finding only when the governing policy is not
1826
+ * `allow`; this turns that policy into what the gate should DO with the
1827
+ * finding — independent of the finding's impact severity:
1828
+ *
1829
+ * - `reject` → `refuse` (operator chose to reject this class outright)
1830
+ * - `audit` / `audit-only` → `audit` (observe, do not block or alter)
1831
+ * - a known mitigation (`strip`, `prefix-tab`, `prefix-quote`,
1832
+ * `wrap-with-quotes-and-prefix`, `allowlist`, `redact`, `trim`) →
1833
+ * `sanitize` (the guard's sanitizer performs the chosen transform)
1834
+ *
1835
+ * Fails CLOSED: an unrecognized policy value (a typo such as `rejet`, or a
1836
+ * mitigation name not in the known set) maps to `refuse`, never `sanitize` —
1837
+ * a misconfiguration must not silently downgrade a finding to serve-after-
1838
+ * best-effort. Add a new mitigation to MITIGATION_POLICIES when one ships.
1839
+ *
1840
+ * @example
1841
+ * b.gateContract.policyDisposition("reject"); // → "refuse"
1842
+ * b.gateContract.policyDisposition("strip"); // → "sanitize"
1843
+ * b.gateContract.policyDisposition("audit-only"); // → "audit"
1844
+ * b.gateContract.policyDisposition("rejet"); // → "refuse" (fail closed)
1845
+ */
1846
+ var MITIGATION_POLICIES = Object.freeze({
1847
+ strip: true, "prefix-tab": true, "prefix-quote": true,
1848
+ "wrap-with-quotes-and-prefix": true, allowlist: true, redact: true, trim: true,
1849
+ });
1850
+ function policyDisposition(policy) {
1851
+ if (policy === "reject") return "refuse";
1852
+ if (policy === "audit" || policy === "audit-only") return "audit";
1853
+ if (MITIGATION_POLICIES[policy] === true) return "sanitize";
1854
+ return "refuse";
1855
+ }
1856
+
1857
+ /**
1858
+ * @primitive b.gateContract.charThreatDisposition
1859
+ * @signature b.gateContract.charThreatDisposition(issue, opts)
1860
+ * @since 0.15.13
1861
+ * @status stable
1862
+ * @related b.gateContract.policyDisposition, b.codepointClass.detectCharThreats
1863
+ *
1864
+ * Gate disposition for the shared character-threat findings every content
1865
+ * guard collects via `codepointClass.detectCharThreats` — `bidi-override`,
1866
+ * `null-byte`, `control-char` — resolved from the guard's per-class policy
1867
+ * (`bidiPolicy` / `nullBytePolicy` / `controlPolicy`). Returns `null` for any
1868
+ * other kind so a guard's own `dispositionFor` can fall through to it for the
1869
+ * shared kinds and handle its guard-specific findings itself.
1870
+ *
1871
+ * @opts
1872
+ * bidiPolicy: string, // governs the bidi-override finding
1873
+ * nullBytePolicy: string, // governs the null-byte finding
1874
+ * controlPolicy: string, // governs the control-char finding
1875
+ * zeroWidthPolicy: string, // governs the zero-width finding
1876
+ *
1877
+ * @example
1878
+ * function dispositionFor(issue, opts) {
1879
+ * return b.gateContract.charThreatDisposition(issue, opts) ||
1880
+ * mySpecificMapping(issue, opts);
1881
+ * }
1882
+ */
1883
+ function charThreatDisposition(issue, opts) {
1884
+ switch (issue.kind) {
1885
+ case "bidi-override": return policyDisposition(opts.bidiPolicy);
1886
+ case "null-byte": return policyDisposition(opts.nullBytePolicy);
1887
+ case "control-char": return policyDisposition(opts.controlPolicy);
1888
+ case "zero-width": return policyDisposition(opts.zeroWidthPolicy);
1889
+ default: return null;
1890
+ }
1891
+ }
1892
+
1389
1893
  /**
1390
1894
  * @primitive b.gateContract.aggregateIssues
1391
1895
  * @signature b.gateContract.aggregateIssues(issues)
@@ -1439,34 +1943,159 @@ function aggregateIssues(issues) {
1439
1943
  * bad.issues[0].kind; // → "bad-input"
1440
1944
  */
1441
1945
  function badInputResultIfNotStringOrBuffer(input) {
1442
- if (typeof input === "string" || Buffer.isBuffer(input)) return null;
1946
+ // The "bytes" input contract IS this check compose it so there is one
1947
+ // source of truth for "string or Buffer, else bad-input".
1948
+ var extracted = INPUT_CONTRACTS.bytes(input);
1949
+ if (!extracted.badInput) return null;
1443
1950
  return {
1444
1951
  ok: false,
1445
1952
  issues: [{ kind: "bad-input", severity: "high",
1446
- snippet: "input is not string or Buffer" }],
1953
+ snippet: extracted.badInput }],
1447
1954
  };
1448
1955
  }
1449
1956
 
1957
+ /**
1958
+ * @primitive b.gateContract.detectStringInput
1959
+ * @signature b.gateContract.detectStringInput(input, opts, cfg)
1960
+ * @since 0.15.13
1961
+ * @status stable
1962
+ * @related b.gateContract.badInputResultIfNotStringOrBuffer, b.codepointClass.detectCharThreats
1963
+ *
1964
+ * The whole detector preamble every `raw`-contract string guard opens with:
1965
+ * reject a non-string input, then an empty one, then one over the byte cap,
1966
+ * else collect the codepoint-class threats (BIDI / control / null / zero-width)
1967
+ * the guard then appends its own findings to. A guard on the `raw` input
1968
+ * contract owns its own input check (see `INPUT_CONTRACTS`); this builds that
1969
+ * preamble once, guard-named, instead of re-spelling its four steps in every
1970
+ * `_detectIssues`. Returns `{ done, issues }`: when `done` the detector returns
1971
+ * `issues` verbatim (the `<name>.bad-input` / `<name>.empty` / cap issue, or
1972
+ * `[]` for a legal empty); when not `done`, `issues` is the codepoint-threat
1973
+ * list the detector continues from. The byte cap runs before the codepoint
1974
+ * scan so a huge input is rejected before the O(n) scan.
1975
+ *
1976
+ * The cap's divergence is data, not branching: `cap.bytes` is the limit (the
1977
+ * guard's resolved `maxBytes` / `maxPatternBytes` / `maxDomainOctets`),
1978
+ * `cap.kind` the issue kind (default `<name>-cap`), and `cap.snippet` the
1979
+ * message — a string, or a `function(byteLen, bytes)` when it embeds the
1980
+ * measured length. Omit `cap` for a guard with no byte cap.
1981
+ *
1982
+ * @opts
1983
+ * {
1984
+ * name: string, // required: the guard name — ruleId prefix + default noun
1985
+ * noun: string, // default name — the subject word in the bad-input/empty snippet
1986
+ * emptyMode: string, // "issue" (default) → <name>.empty issue · "ok" → [] (empty is legal) · "skip" → no empty check
1987
+ * cap: { // omit when the guard has no byte cap
1988
+ * bytes: number, // required: the byte limit
1989
+ * kind: string, // default "<name>-cap" — the cap issue kind (and ruleId suffix)
1990
+ * snippet: string|function, // default "<noun> input exceeds maxBytes <bytes>"; fn(byteLen, bytes) when it needs the measured length
1991
+ * },
1992
+ * scanCodepoints: boolean, // default true: the not-done result carries the codepoint-class scan. Pass false for a guard that scans codepoints later in its own detection (or parses them via its format, e.g. JSON) — the not-done result is then `[]`.
1993
+ * }
1994
+ *
1995
+ * @example
1996
+ * function _detectIssues(input, opts) {
1997
+ * var pre = b.gateContract.detectStringInput(input, opts, {
1998
+ * name: "cidr", cap: { bytes: opts.maxBytes },
1999
+ * });
2000
+ * if (pre.done) return pre.issues;
2001
+ * var issues = pre.issues; // codepoint-class threats so far
2002
+ * // … guard-specific detection appends to issues …
2003
+ * return issues;
2004
+ * }
2005
+ */
2006
+ function detectStringInput(input, opts, cfg) {
2007
+ validateOpts.requireObject(cfg, "gateContract.detectStringInput", GateContractError);
2008
+ validateOpts.requireNonEmptyString(cfg.name,
2009
+ "gateContract.detectStringInput: cfg.name", GateContractError, "gate-contract/bad-opt");
2010
+ var noun = cfg.noun || cfg.name;
2011
+ if (typeof input !== "string") {
2012
+ return { done: true, issues: [{ kind: "bad-input", severity: "high",
2013
+ ruleId: cfg.name + ".bad-input", snippet: noun + " is not a string" }] };
2014
+ }
2015
+ var emptyMode = cfg.emptyMode || "issue";
2016
+ if (emptyMode !== "skip" && input.length === 0) {
2017
+ return { done: true, issues: emptyMode === "ok" ? [] :
2018
+ [{ kind: "empty", severity: "high", ruleId: cfg.name + ".empty",
2019
+ snippet: noun + " is empty" }] };
2020
+ }
2021
+ if (cfg.cap) {
2022
+ var byteLen = Buffer.byteLength(input, "utf8");
2023
+ if (byteLen > cfg.cap.bytes) {
2024
+ var capKind = cfg.cap.kind || (cfg.name + "-cap");
2025
+ var capSnippet = typeof cfg.cap.snippet === "function"
2026
+ ? cfg.cap.snippet(byteLen, cfg.cap.bytes)
2027
+ : (cfg.cap.snippet || (noun + " input exceeds maxBytes " + cfg.cap.bytes));
2028
+ return { done: true, issues: [{ kind: capKind, severity: "high",
2029
+ ruleId: cfg.name + "." + capKind, snippet: capSnippet }] };
2030
+ }
2031
+ }
2032
+ if (cfg.scanCodepoints === false) return { done: false, issues: [] };
2033
+ return { done: false, issues: codepointClass.detectCharThreats(input, opts, cfg.name) };
2034
+ }
2035
+
2036
+ // Input contracts — the one place that knows how to turn a raw guard input
2037
+ // into the subject its detector expects (or flag bad input). Every guard's
2038
+ // `validate` differs only in its input shape; the contract captures that
2039
+ // difference so one `runIssueValidator` serves them all:
2040
+ //
2041
+ // - "text": string / Buffer → UTF-8 text; anything else is bad input. The
2042
+ // content guards (csv / html / markdown / json / ...) whose detector takes
2043
+ // a string but does NOT type-check it themselves.
2044
+ // - "bytes": string / Buffer is accepted and reaches the detector UNCHANGED
2045
+ // (no utf8 coercion); anything else is bad input. The guards that inspect
2046
+ // raw bytes before decoding (filename overlong-UTF-8, sql encoding gate) —
2047
+ // converting to text first would hide the very bytes they check. This is
2048
+ // exactly `badInputResultIfNotStringOrBuffer(input) ||
2049
+ // aggregateIssues(detect(input))`.
2050
+ // - "raw" (default): identity — the value reaches the detector untouched and
2051
+ // the detector owns its own (often typed) bad-input. The object-bag guards
2052
+ // (image / pdf metadata, archive entries) and the string guards whose
2053
+ // detector type-checks itself (email). This is exactly
2054
+ // `aggregateIssues(detect(input))`.
2055
+ //
2056
+ // A guard with a bespoke shape passes its own `function(input){ return
2057
+ // { subject } | { badInput: msg } }` instead of a name. New input shapes
2058
+ // extend the class by adding a contract, never by branching in defineGuard.
2059
+ var INPUT_CONTRACTS = {
2060
+ text: function (input) {
2061
+ if (typeof input === "string") return { subject: input };
2062
+ if (Buffer.isBuffer(input)) return { subject: input.toString("utf8") };
2063
+ return { badInput: "input is not string or Buffer" };
2064
+ },
2065
+ bytes: function (input) {
2066
+ if (typeof input === "string" || Buffer.isBuffer(input)) return { subject: input };
2067
+ return { badInput: "input is not string or Buffer" };
2068
+ },
2069
+ raw: function (input) { return { subject: input }; },
2070
+ };
2071
+ Object.freeze(INPUT_CONTRACTS);
2072
+
2073
+ function resolveInputContract(contract) {
2074
+ if (typeof contract === "function") return contract;
2075
+ return INPUT_CONTRACTS[contract] || INPUT_CONTRACTS.text;
2076
+ }
2077
+
1450
2078
  /**
1451
2079
  * @primitive b.gateContract.runIssueValidator
1452
- * @signature b.gateContract.runIssueValidator(input, opts, detector)
2080
+ * @signature b.gateContract.runIssueValidator(input, opts, detector, contract?)
1453
2081
  * @since 0.7.5
1454
2082
  * @status stable
1455
2083
  * @related b.gateContract.aggregateIssues, b.gateContract.badInputResultIfNotStringOrBuffer
1456
2084
  *
1457
- * Boilerplate for guard-* `validate(input, opts)` entry points.
1458
- * Normalizes string-or-Buffer input to a UTF-8 string, returns the
1459
- * canonical `{ ok: false, issues: [{ kind: "bad-input", ... }] }` shape
1460
- * on type mismatch, otherwise calls the operator-supplied `detector`
1461
- * and aggregates its issues array. Result `ok` is `true` only when no
1462
- * detected issue is `critical` / `high` severity. Lets every guard's
1463
- * `validate()` body be identical scaffolding around the per-guard
1464
- * detector. The `opts` argument is forwarded verbatim as the second
1465
- * argument to `detector(text, opts)` its shape is detector-defined,
1466
- * not constrained by gate-contract.
2085
+ * The single `validate(input, opts)` engine for the whole guard family. An
2086
+ * input contract normalizes the raw input to the subject the detector expects
2087
+ * (or flags bad input), then the detector runs and its issues aggregate. One
2088
+ * engine spans every input shape in the family: `"text"` (the default) coerces
2089
+ * string / Buffer to UTF-8 and refuses anything else; `"raw"` hands the value
2090
+ * through so an object-bag or byte-level detector owns its own bad-input
2091
+ * (identical to `aggregateIssues(detector(input, opts))`); a guard with a
2092
+ * bespoke shape passes its own extractor `function(input) -> { subject } |
2093
+ * { badInput: message }`. Result `ok` is `true` only when no detected issue is
2094
+ * `critical` / `high` severity. The `opts` argument is forwarded verbatim as
2095
+ * the detector's second argument — its shape is detector-defined.
1467
2096
  *
1468
2097
  * @opts
1469
- * ...: any, // detector-defined; passed through to detector(text, opts)
2098
+ * ...: any, // detector-defined; passed through to detector(subject, opts)
1470
2099
  *
1471
2100
  * @example
1472
2101
  * function detectFormulaTrigger(text) {
@@ -1481,18 +2110,16 @@ function badInputResultIfNotStringOrBuffer(input) {
1481
2110
  * var ok = b.gateContract.runIssueValidator("ada,36", {}, detectFormulaTrigger);
1482
2111
  * ok.ok; // → true
1483
2112
  */
1484
- function runIssueValidator(input, opts, detector) {
1485
- var text = typeof input === "string"
1486
- ? input
1487
- : (Buffer.isBuffer(input) ? input.toString("utf8") : null);
1488
- if (text == null) {
2113
+ function runIssueValidator(input, opts, detector, contract) {
2114
+ var extracted = resolveInputContract(contract)(input);
2115
+ if (extracted && typeof extracted.badInput === "string") {
1489
2116
  return {
1490
2117
  ok: false,
1491
2118
  issues: [{ kind: "bad-input", severity: "high",
1492
- snippet: "input is not string or Buffer" }],
2119
+ snippet: extracted.badInput }],
1493
2120
  };
1494
2121
  }
1495
- return aggregateIssues(detector(text, opts));
2122
+ return aggregateIssues(detector(extracted.subject, opts));
1496
2123
  }
1497
2124
 
1498
2125
  /**
@@ -1910,8 +2537,10 @@ function _ctxValueForKind(kind, ctx, override) {
1910
2537
  * errorName: string, // defineClass name (mutually exclusive with errorClass)
1911
2538
  * errorClass: function, // pre-built FrameworkError subclass
1912
2539
  * profiles: object, // PROFILES (must include strict/balanced/permissive); required
1913
- * defaults: object, // DEFAULTS baseline (default profiles.strict)
1914
- * postures: object, // COMPLIANCE_POSTURES (default ALL_STRICT_POSTURES)
2540
+ * defaults: object, // DEFAULTS baseline (default profiles.strict, or strictDefaults(profiles, defaultsOverlay) when `base` is given)
2541
+ * postures: object, // COMPLIANCE_POSTURES (default ALL_STRICT_POSTURES, or compliancePostures(profiles, { base }) when `base` is given)
2542
+ * base: number, // forensic snippet budget — when given (and defaults/postures omitted), the factory derives both via strictDefaults + compliancePostures
2543
+ * defaultsOverlay: object, // per-guard default overrides merged into the derived strictDefaults (e.g. { maxRuntimeMs: ... }); only used with `base`
1915
2544
  * mimeTypes: string[], // content guards only
1916
2545
  * extensions: string[], // content guards only
1917
2546
  * integrationFixtures: object, // INTEGRATION_FIXTURES (consumed by host harness)
@@ -1953,9 +2582,6 @@ function defineGuard(spec) {
1953
2582
  }
1954
2583
  validateOpts.requireObject(spec.profiles, "gateContract.defineGuard: profiles",
1955
2584
  GateContractError);
1956
- if (typeof spec.validate !== "function") {
1957
- throw _err("gate-contract/bad-opt", "defineGuard: validate must be a function");
1958
- }
1959
2585
  if (spec.errorClass && spec.errorName) {
1960
2586
  throw _err("gate-contract/bad-opt",
1961
2587
  "defineGuard: pass errorClass OR errorName, not both");
@@ -1967,8 +2593,130 @@ function defineGuard(spec) {
1967
2593
  spec.name.charAt(0).toUpperCase() + spec.name.slice(1) + "Error"),
1968
2594
  { alwaysPermanent: true });
1969
2595
  var profiles = spec.profiles;
1970
- var defaults = spec.defaults || profiles.strict || {};
1971
- var postures = spec.postures || ALL_STRICT_POSTURES;
2596
+ // A guard may hand `defaults` / `postures` explicitly, OR pass `base` (the
2597
+ // forensic snippet budget) and let the factory derive the standard config —
2598
+ // `strictDefaults(profiles, defaultsOverlay)` + `compliancePostures(profiles,
2599
+ // { base })` — so the guard file needn't declare the two module-vars itself.
2600
+ var defaults = spec.defaults ||
2601
+ (typeof spec.base === "number" ? strictDefaults(profiles, spec.defaultsOverlay)
2602
+ : (profiles.strict || {}));
2603
+ var postures = spec.postures ||
2604
+ (typeof spec.base === "number" ? compliancePostures(profiles, { base: spec.base })
2605
+ : ALL_STRICT_POSTURES);
2606
+
2607
+ // Dynamic guard assembly — the upstream primitive absorbs the per-guard
2608
+ // binding wrappers. A guard may pass a raw `detect(input, opts) -> issues[]`
2609
+ // (the guard-specific detection logic) plus an optional `sanitizeTransform(
2610
+ // input, resolvedOpts) -> value`, instead of hand-rolling `_resolveOpts`,
2611
+ // `validate`, and the `sanitize` resolve→detect→throw boilerplate that every
2612
+ // guard otherwise duplicates. defineGuard already owns the profile/posture/
2613
+ // defaults/errorClass/prefix, so it binds the resolver here and builds
2614
+ // validate + sanitize. Behaviour matches the hand-written wrappers exactly:
2615
+ // validate runs detect on the RAW opts (detect resolves what it needs);
2616
+ // sanitize resolves first, then detect → throwOnRefusalSeverity → transform.
2617
+ // The bound profile/posture resolver — built once from the spec's binding
2618
+ // config (profiles/postures/defaults/errorClass/prefix) and EXPOSED on the
2619
+ // guard as `resolveOpts` (below), so a bespoke gate calls
2620
+ // `module.exports.resolveOpts(opts)` instead of each guard hand-rolling the
2621
+ // identical `function _resolveOpts(o){ return resolveProfileAndPosture(o,
2622
+ // {...}) }` binding wrapper. The binding config lives in ONE place.
2623
+ var _resolveGuardOpts = function (o) {
2624
+ return resolveProfileAndPosture(o || {}, {
2625
+ profiles: profiles,
2626
+ compliancePostures: postures,
2627
+ defaults: defaults,
2628
+ errorClass: ErrorClass,
2629
+ errCodePrefix: prefix,
2630
+ });
2631
+ };
2632
+ if (typeof spec.detect === "function") {
2633
+ var intOpts = Array.isArray(spec.intOpts) ? spec.intOpts.slice() : null;
2634
+ if (typeof spec.validate !== "function") {
2635
+ spec.validate = function (input, opts) {
2636
+ var resolved = _resolveGuardOpts(opts);
2637
+ if (intOpts) {
2638
+ numericBounds.requireAllPositiveFiniteIntIfPresent(resolved, intOpts,
2639
+ spec.name + ".validate", ErrorClass, prefix + ".bad-opt");
2640
+ }
2641
+ // One engine, the guard's input contract picks the shape. Default
2642
+ // "raw" reproduces the historical aggregateIssues(detect(input)) — the
2643
+ // detector owns its own bad-input (object-bag guards image/pdf, the
2644
+ // byte-level guards). A guard whose detector takes a string but does
2645
+ // not type-check it (e.g. csv returns [] on a non-string) sets
2646
+ // inputContract: "text" so non-text input is refused as bad-input.
2647
+ return runIssueValidator(input, resolved, spec.detect,
2648
+ spec.inputContract || "raw");
2649
+ };
2650
+ }
2651
+ if (typeof spec.sanitizeTransform === "function" && typeof spec.sanitize !== "function") {
2652
+ // spec.sanitizeSeverities narrows which severities REFUSE (throw) vs are
2653
+ // stripped/repaired by sanitizeTransform. Default ['critical','high'];
2654
+ // a guard that repairs high-severity findings and refuses only the
2655
+ // unrepairable critical shapes (markdown / email / xml / yaml) passes
2656
+ // ['critical'] so the generated sanitize matches its hand-written one.
2657
+ // An empty array means "strip unconditionally, never refuse" (csv / text
2658
+ // best-effort scrubbers, whose sanitize never throws on a detected issue).
2659
+ var sanitizeSeverities = Array.isArray(spec.sanitizeSeverities)
2660
+ ? spec.sanitizeSeverities.slice() : null;
2661
+ var refusesOnDetect = sanitizeSeverities === null || sanitizeSeverities.length > 0;
2662
+ // spec.sanitizeAmplificationCap (a string = the resolved-opts field name
2663
+ // carrying the max growth ratio) opts the guard into the "sanitize must
2664
+ // shrink, never grow" post-condition: the transform runs on extracted
2665
+ // text and the output length is capped at ratio×input. Used by the text
2666
+ // scrubbers (csv / text) whose hand-written sanitize threw
2667
+ // `<prefix>.sanitize-amplified`. When unset, sanitize keeps the raw input
2668
+ // (binary passthrough guards image / pdf must not be utf8-decoded).
2669
+ var ampCapField = typeof spec.sanitizeAmplificationCap === "string"
2670
+ ? spec.sanitizeAmplificationCap : null;
2671
+ spec.sanitize = function (input, opts) {
2672
+ var resolved = _resolveGuardOpts(opts);
2673
+ var subject = input;
2674
+ if (ampCapField) {
2675
+ // Same text contract the validate engine uses — string/Buffer→text,
2676
+ // refuse anything else (here as a throw, sanitize's contract).
2677
+ var extracted = INPUT_CONTRACTS.text(input);
2678
+ if (extracted.badInput) {
2679
+ throw ErrorClass.factory(prefix + ".bad-input",
2680
+ "sanitize requires string or Buffer input");
2681
+ }
2682
+ subject = extracted.subject;
2683
+ }
2684
+ if (refusesOnDetect) {
2685
+ var issues = spec.detect(subject, resolved);
2686
+ // A `bad-input` issue means the input is UNPROCESSABLE (wrong type /
2687
+ // shape), not a content finding — a scrubber must never let it slip
2688
+ // into the transform (which would return the garbage verbatim). So it
2689
+ // refuses ALWAYS, independent of which CONTENT severities this guard's
2690
+ // sanitize tolerates via sanitizeSeverities. (csv/text reach the same
2691
+ // refusal earlier through the ampCapField text contract above.)
2692
+ for (var bi = 0; bi < issues.length; bi += 1) {
2693
+ if (issues[bi].kind === "bad-input") {
2694
+ throw ErrorClass.factory(prefix + ".bad-input",
2695
+ issues[bi].snippet || "sanitize: input is not processable");
2696
+ }
2697
+ }
2698
+ var throwOpts = { errorClass: ErrorClass, codePrefix: prefix };
2699
+ if (sanitizeSeverities) throwOpts.severities = sanitizeSeverities;
2700
+ throwOnRefusalSeverity(issues, throwOpts);
2701
+ }
2702
+ var out = spec.sanitizeTransform(subject, resolved);
2703
+ if (ampCapField) {
2704
+ var cap = resolved[ampCapField];
2705
+ if (typeof cap === "number") {
2706
+ var amp = out.length / Math.max(subject.length, 1);
2707
+ if (amp > cap) {
2708
+ throw ErrorClass.factory(prefix + ".sanitize-amplified",
2709
+ "sanitize grew output " + amp.toFixed(2) + "x; cap " + cap);
2710
+ }
2711
+ }
2712
+ }
2713
+ return out;
2714
+ };
2715
+ }
2716
+ }
2717
+ if (typeof spec.validate !== "function") {
2718
+ throw _err("gate-contract/bad-opt", "defineGuard: validate (or detect) must be a function");
2719
+ }
1972
2720
 
1973
2721
  var buildProfileFn = makeProfileBuilder(profiles);
1974
2722
  function compliancePostureFn(name) {
@@ -2012,12 +2760,7 @@ function defineGuard(spec) {
2012
2760
  var value = _ctxValueForKind(spec.kind, ctx, ctxFields);
2013
2761
  if (!value) return { ok: true, action: "serve" };
2014
2762
  var rv = spec.validate(value, opts);
2015
- if (!rv.issues || rv.issues.length === 0) return { ok: true, action: "serve" };
2016
- var hasBlocking = rv.issues.some(function (i) {
2017
- return i.severity === "critical" || i.severity === "high";
2018
- });
2019
- if (!hasBlocking) return { ok: true, action: "audit-only", issues: rv.issues };
2020
- return { ok: false, action: "refuse", issues: rv.issues };
2763
+ return severityDisposition(rv.issues || []);
2021
2764
  };
2022
2765
  return buildGuardGate(
2023
2766
  opts.name || (gateNamePrefix + ":" + (opts.profile || "default")),
@@ -2031,6 +2774,7 @@ function defineGuard(spec) {
2031
2774
  NAME: spec.name,
2032
2775
  KIND: spec.kind,
2033
2776
  validate: spec.validate,
2777
+ resolveOpts: _resolveGuardOpts,
2034
2778
  buildProfile: buildProfileFn,
2035
2779
  compliancePosture: compliancePostureFn,
2036
2780
  loadRulePack: rulePacks.load,
@@ -2259,6 +3003,81 @@ function defineParser(spec) {
2259
3003
  * decision.action; // → "serve" | "refuse" | …
2260
3004
  */
2261
3005
 
3006
+ /**
3007
+ * @abiTemplate defineGuard
3008
+ * @method validate
3009
+ * @signature b.{NS}.validate(input, opts?)
3010
+ * @status stable
3011
+ * @related b.{NS}.gate, b.{NS}.sanitize
3012
+ *
3013
+ * Inspect `input` under a resolved profile + compliance posture and return a
3014
+ * structured result `{ ok, issues }` WITHOUT throwing — `ok` is false when any
3015
+ * `high` / `critical` issue fired, and `issues` lists every finding (kind,
3016
+ * severity, ruleId, snippet). `opts` selects the `profile` /
3017
+ * `compliancePosture`; omitted opts use this guard's default profile. Wired by
3018
+ * `gateContract.defineGuard` from the guard's detection logic through
3019
+ * `gateContract.aggregateIssues`, so the result shape and severity gating are
3020
+ * identical across the guard family.
3021
+ *
3022
+ * @opts
3023
+ * profile: string, // one of PROFILES; default this guard's default
3024
+ * compliancePosture: string, // overlay one of hipaa/pci-dss/gdpr/soc2
3025
+ *
3026
+ * @example
3027
+ * var rv = b.{NS}.validate(input, { profile: "strict" });
3028
+ * rv.ok; // → true | false
3029
+ * rv.issues; // → [ { kind, severity, … }, … ]
3030
+ */
3031
+
3032
+ /**
3033
+ * @abiTemplate defineGuard
3034
+ * @method sanitize
3035
+ * @signature b.{NS}.sanitize(input, opts?)
3036
+ * @status stable
3037
+ * @related b.{NS}.validate, b.{NS}.gate
3038
+ *
3039
+ * Return a normalized form of `input` when no `high` / `critical` issue fires;
3040
+ * throw `{ERR}` on any such refusal (best-effort repair, never a silent pass).
3041
+ * Resolves the profile + posture, runs the guard's detection, throws via
3042
+ * `gateContract.throwOnRefusalSeverity` on a refusal, then applies the guard's
3043
+ * own safe transform. Wired by `gateContract.defineGuard`, so the
3044
+ * resolve → detect → throw → transform order is identical across the family; a
3045
+ * guard with no safe transform ships no `sanitize`.
3046
+ *
3047
+ * @opts
3048
+ * profile: string, // one of PROFILES; default this guard's default
3049
+ * compliancePosture: string, // overlay one of hipaa/pci-dss/gdpr/soc2
3050
+ *
3051
+ * @example
3052
+ * var safe = b.{NS}.sanitize(input, { profile: "permissive" });
3053
+ * safe; // → normalized value
3054
+ */
3055
+
3056
+ /**
3057
+ * @abiTemplate defineGuard
3058
+ * @method resolveOpts
3059
+ * @signature b.{NS}.resolveOpts(opts?)
3060
+ * @status stable
3061
+ * @related b.{NS}.validate, b.{NS}.gate
3062
+ *
3063
+ * Resolve caller `opts` against this guard's `PROFILES` + compliance-posture
3064
+ * overlays into the fully-defaulted option set the guard runs on — the same
3065
+ * resolution `validate` / `sanitize` / `gate` apply internally. Wired by
3066
+ * `gateContract.defineGuard` from the guard's binding config (profiles /
3067
+ * postures / defaults / error class), so a guard's bespoke `gate` calls
3068
+ * `resolveOpts` instead of re-declaring the per-guard resolver wrapper. Throws
3069
+ * `{ERR}` with code `"{CODE}.bad-opt"` / `"{CODE}.bad-posture"` on an unknown
3070
+ * profile or posture name.
3071
+ *
3072
+ * @opts
3073
+ * profile: string, // one of PROFILES; default this guard's default
3074
+ * compliancePosture: string, // overlay one of hipaa/pci-dss/gdpr/soc2
3075
+ *
3076
+ * @example
3077
+ * var resolved = b.{NS}.resolveOpts({ profile: "strict" });
3078
+ * resolved.profile; // → "strict"
3079
+ */
3080
+
2262
3081
  /**
2263
3082
  * @abiTemplate defineParser
2264
3083
  * @method compliancePosture
@@ -2300,12 +3119,24 @@ module.exports = {
2300
3119
  resolveProfileAndPosture: resolveProfileAndPosture,
2301
3120
  runIssueValidator: runIssueValidator,
2302
3121
  buildGuardGate: buildGuardGate,
3122
+ severityDisposition: severityDisposition,
3123
+ buildContentGate: buildContentGate,
3124
+ policyDisposition: policyDisposition,
3125
+ charThreatDisposition: charThreatDisposition,
2303
3126
  extractBytesAsText: extractBytesAsText,
2304
3127
  lookupCompliancePosture: lookupCompliancePosture,
2305
3128
  ALL_STRICT_POSTURES: ALL_STRICT_POSTURES,
3129
+ CHAR_THREATS_REJECT_ALL: CHAR_THREATS_REJECT_ALL,
3130
+ DANGEROUS_URL_SCHEMES: DANGEROUS_URL_SCHEMES,
3131
+ SAFE_URL_SCHEMES: SAFE_URL_SCHEMES,
3132
+ identifierFixtures: identifierFixtures,
3133
+ compliancePostures: compliancePostures,
3134
+ strictDefaults: strictDefaults,
3135
+ detectStringInput: detectStringInput,
2306
3136
  makeRulePackLoader: makeRulePackLoader,
2307
3137
  makeProfileBuilder: makeProfileBuilder,
2308
3138
  makeProfileResolver: makeProfileResolver,
3139
+ resolveProfileName: resolveProfileName,
2309
3140
  throwOnRefusalSeverity: throwOnRefusalSeverity,
2310
3141
  badInputResultIfNotStringOrBuffer: badInputResultIfNotStringOrBuffer,
2311
3142
  aggregateIssues: aggregateIssues,