@blamejs/blamejs-shop 0.4.30 → 0.4.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/checkout.js +8 -0
  4. package/lib/order.js +71 -11
  5. package/lib/vendor/MANIFEST.json +392 -278
  6. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  7. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  8. package/lib/vendor/blamejs/.gitignore +6 -0
  9. package/lib/vendor/blamejs/CHANGELOG.md +26 -0
  10. package/lib/vendor/blamejs/MIGRATING.md +43 -0
  11. package/lib/vendor/blamejs/README.md +8 -6
  12. package/lib/vendor/blamejs/SECURITY.md +19 -3
  13. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  14. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  15. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  16. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  17. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  18. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  19. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  20. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  21. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  23. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  24. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  25. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  26. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  27. package/lib/vendor/blamejs/index.js +4 -0
  28. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  29. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  30. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  31. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  32. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  33. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  34. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  35. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  36. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  37. package/lib/vendor/blamejs/lib/audit.js +259 -123
  38. package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
  39. package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
  40. package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
  41. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
  42. package/lib/vendor/blamejs/lib/backup/index.js +45 -10
  43. package/lib/vendor/blamejs/lib/break-glass.js +355 -147
  44. package/lib/vendor/blamejs/lib/cache.js +174 -105
  45. package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
  46. package/lib/vendor/blamejs/lib/cli.js +19 -14
  47. package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
  48. package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
  49. package/lib/vendor/blamejs/lib/cluster.js +119 -71
  50. package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
  51. package/lib/vendor/blamejs/lib/compliance.js +206 -4
  52. package/lib/vendor/blamejs/lib/consent.js +82 -29
  53. package/lib/vendor/blamejs/lib/constants.js +27 -11
  54. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  55. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  56. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  57. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  58. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  59. package/lib/vendor/blamejs/lib/db.js +249 -99
  60. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  61. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  62. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  63. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  64. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  65. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  66. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  67. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  68. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  69. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  70. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  71. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  72. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  73. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  74. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  75. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  76. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  77. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  78. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  79. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  80. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  81. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  82. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  83. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  84. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  85. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  86. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  87. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  88. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  89. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  90. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  91. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  92. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  93. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  94. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  95. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  96. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  97. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  98. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  99. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  100. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  101. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  102. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  103. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  104. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  105. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  106. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  107. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  108. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  109. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  110. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  111. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  112. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  113. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  114. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  115. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  116. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  117. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  118. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  119. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  120. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  121. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  122. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  123. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  124. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  125. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  126. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  127. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  128. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  129. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  131. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  132. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  133. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  134. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  135. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  136. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  137. package/lib/vendor/blamejs/lib/mail.js +8 -4
  138. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  139. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  140. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  141. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  142. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  143. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  144. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  145. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  146. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  147. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  148. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  149. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  150. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  151. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  152. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  153. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  154. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  155. package/lib/vendor/blamejs/lib/observability.js +124 -0
  156. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  157. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  158. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  159. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  160. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  161. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  162. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  163. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  164. package/lib/vendor/blamejs/lib/queue.js +7 -0
  165. package/lib/vendor/blamejs/lib/redact.js +68 -11
  166. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  167. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  168. package/lib/vendor/blamejs/lib/retention.js +101 -40
  169. package/lib/vendor/blamejs/lib/router.js +212 -5
  170. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  171. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  172. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  173. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  174. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  175. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  176. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  177. package/lib/vendor/blamejs/lib/scheduler.js +35 -12
  178. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  179. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  180. package/lib/vendor/blamejs/lib/session.js +175 -77
  181. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  182. package/lib/vendor/blamejs/lib/sse.js +26 -0
  183. package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
  184. package/lib/vendor/blamejs/lib/static.js +177 -34
  185. package/lib/vendor/blamejs/lib/subject.js +96 -49
  186. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  187. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  188. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  189. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  190. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  191. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  192. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  193. package/lib/vendor/blamejs/package.json +2 -2
  194. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  195. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  200. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  201. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  202. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  203. package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
  204. package/lib/vendor/blamejs/scripts/release.js +398 -38
  205. package/lib/vendor/blamejs/test/00-primitives.js +117 -0
  206. package/lib/vendor/blamejs/test/10-state.js +140 -14
  207. package/lib/vendor/blamejs/test/20-db.js +65 -2
  208. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  209. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  210. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  211. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  212. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  213. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  214. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  215. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  216. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  217. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  220. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  221. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  222. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  223. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  224. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  225. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  226. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  227. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  228. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  229. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  230. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  231. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  232. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  233. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  234. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  235. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  236. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  237. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  238. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  240. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  250. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
  251. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  256. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  259. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  260. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  261. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  272. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  273. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  274. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  275. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  277. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  278. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  279. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  280. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  282. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  283. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  284. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  285. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  293. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  304. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  310. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  312. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  313. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  314. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  315. package/lib/vendor/blamejs/test/smoke.js +79 -21
  316. package/package.json +1 -1
  317. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  318. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  319. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  320. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  321. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  322. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  323. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  324. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  325. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  326. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  327. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  328. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  329. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  330. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  331. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  332. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  333. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  334. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  335. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  336. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  337. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  338. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -46,6 +46,7 @@ var C = require("./constants");
46
46
  var lazyRequire = require("./lazy-require");
47
47
  var validateOpts = require("./validate-opts");
48
48
  var safeSql = require("./safe-sql");
49
+ var sql = require("./sql");
49
50
  var { defineClass } = require("./framework-error");
50
51
 
51
52
  var audit = lazyRequire(function () { return require("./audit"); });
@@ -55,6 +56,25 @@ var legalHold = lazyRequire(function () { return require("./legal-hold"); });
55
56
  var RetentionError = defineClass("RetentionError", { alwaysPermanent: true });
56
57
  var _err = RetentionError.factory;
57
58
 
59
+ // Resolve the b.sql dialect for the operator-supplied handle. The framework's
60
+ // local b.db handle is always node:sqlite (db.js pins { dialect: "sqlite",
61
+ // quoteName: true }) and exposes no .dialect, so this defaults to "sqlite" —
62
+ // every sweep statement runs against that handle via .prepare(). An operator
63
+ // handle that DOES advertise a dialect (string or () -> string) has it
64
+ // threaded through so the emitted identifier quoting + idioms match the
65
+ // backend the handle dispatches to. quoteName stays on for every retention
66
+ // statement: the rule's table / ageField / softDeleteField identifiers are
67
+ // validated then quoted by construction (no clusterStorage prefix rewrite on
68
+ // this operator-app-schema path).
69
+ function _handleDialect(db) {
70
+ if (db && typeof db.dialect === "function") {
71
+ try { var d = db.dialect(); return typeof d === "string" ? d : "sqlite"; }
72
+ catch (_e) { return "sqlite"; }
73
+ }
74
+ if (db && typeof db.dialect === "string") return db.dialect;
75
+ return "sqlite";
76
+ }
77
+
58
78
  // Identifier-level SQLi defense: every operator-supplied table name,
59
79
  // column name, and cascade FK must pass safeSql.validateIdentifier
60
80
  // before reaching SQL string concatenation. Without this gate a
@@ -196,6 +216,11 @@ function create(opts) {
196
216
  throw _err("BAD_OPT", "create: opts.db is required (a b.db handle with .prepare(sql))");
197
217
  }
198
218
  var db = opts.db;
219
+ // b.sql opts for every retention statement built against this handle. The
220
+ // dialect tracks the handle (sqlite for the framework's local b.db); the
221
+ // validated operator identifiers are quoted by construction (quoteName)
222
+ // with no clusterStorage prefix rewrite on this path.
223
+ var SQL_OPTS = { dialect: _handleDialect(db), quoteName: true };
199
224
  var auditOn = opts.audit !== false && opts.audit != null;
200
225
  var auditInstance = (opts.audit && opts.audit !== true) ? opts.audit : null;
201
226
  var rules = {};
@@ -235,21 +260,28 @@ function create(opts) {
235
260
 
236
261
  function _hardDelete(table, rowId, dryRun) {
237
262
  if (dryRun) return { wouldDelete: 1 };
238
- var del = db.prepare("DELETE FROM \"" + table + "\" WHERE _id = ?");
239
- del.run(rowId);
263
+ // Operator app table quoteName so the validated identifier emits as a
264
+ // quoted local name; the row id binds as a placeholder.
265
+ var built = sql.delete(table, SQL_OPTS)
266
+ .where("_id", rowId)
267
+ .toSql();
268
+ var del = db.prepare(built.sql);
269
+ del.run.apply(del, built.params);
240
270
  return { deleted: 1 };
241
271
  }
242
272
 
243
273
  function _softDelete(table, rowId, softField, dryRun) {
244
274
  if (dryRun) return { wouldSoftDelete: 1 };
245
- var upd = db.prepare(
246
- "UPDATE \"" + table + "\" SET \"" + softField + "\" = ? WHERE _id = ?");
247
- upd.run(Date.now(), rowId);
275
+ var built = sql.update(table, SQL_OPTS)
276
+ .set(softField, Date.now())
277
+ .where("_id", rowId)
278
+ .toSql();
279
+ var upd = db.prepare(built.sql);
280
+ upd.run.apply(upd, built.params);
248
281
  return { softDeleted: 1 };
249
282
  }
250
283
 
251
284
  function _erase(table, row, dryRun) {
252
- var erased = cryptoField.eraseRow(table, row);
253
285
  var sealedFields = cryptoField.getSealedFields(table) || [];
254
286
  var hashFields = [];
255
287
  var schema = cryptoField.getSchema(table);
@@ -261,21 +293,38 @@ function create(opts) {
261
293
  return _hardDelete(table, row._id, dryRun);
262
294
  }
263
295
  if (dryRun) return { wouldErase: 1, sealedFieldCount: sealedFields.length };
264
- var setClauses = [];
265
- var values = [];
266
- for (var si = 0; si < sealedFields.length; si++) {
267
- setClauses.push('"' + sealedFields[si] + '" = ?');
268
- values.push(null);
269
- }
270
- for (var hi = 0; hi < hashFields.length; hi++) {
271
- setClauses.push('"' + hashFields[hi] + '" = ?');
272
- values.push(null);
296
+ // eraseRow produces the in-memory tombstone AND drives the posture-gated
297
+ // side effects: under a regime whose POSTURE_DEFAULTS sets
298
+ // requireVacuumAfterErase it schedules db.vacuumAfterErase({ mode: "full" })
299
+ // and emits cryptofield.erase.row. Both belong only to the COMMITTING path
300
+ // — running them above the dry-run gate made a preview VACUUM the whole
301
+ // database file per candidate row (#120). Its return value is unused (the
302
+ // UPDATE below NULLs the columns directly); we keep the call for the
303
+ // tombstone bucketing + posture vacuum on the real path.
304
+ var erased = cryptoField.eraseRow(table, row);
305
+ // NULL every sealed column + its derived-hash sibling. b.sql binds each
306
+ // null as a placeholder (the set map preserves the column ordering).
307
+ var eraseSet = {};
308
+ for (var si = 0; si < sealedFields.length; si++) eraseSet[sealedFields[si]] = null;
309
+ for (var hi = 0; hi < hashFields.length; hi++) eraseSet[hashFields[hi]] = null;
310
+ var eraseBuilt = sql.update(table, SQL_OPTS)
311
+ .set(eraseSet)
312
+ .where("_id", row._id)
313
+ .toSql();
314
+ var upd2 = db.prepare(eraseBuilt.sql);
315
+ upd2.run.apply(upd2, eraseBuilt.params);
316
+ // Per-row-key tables (declarePerRowKey): NULLing the sealed columns
317
+ // is not enough — WAL / replica residuals keep the old K_row cells.
318
+ // Destroy the row's wrapped secret so K_row is unrecoverable and the
319
+ // residual ciphertext reads as absent (crypto-shred, GDPR Art. 17).
320
+ // rowId is row._id, the same identity materialize / eraseHard use.
321
+ var perRowKeysDestroyed = 0;
322
+ if (cryptoField.hasPerRowKey(table)) {
323
+ var dr = cryptoField.destroyPerRowKey(table, row._id, db);
324
+ perRowKeysDestroyed = (dr && dr.destroyed) || 0;
273
325
  }
274
- values.push(row._id);
275
- var upd2 = db.prepare("UPDATE \"" + table + "\" SET " + setClauses.join(", ") + " WHERE _id = ?");
276
- upd2.run.apply(upd2, values);
277
326
  void erased;
278
- return { erased: 1, sealedFieldCount: sealedFields.length };
327
+ return { erased: 1, sealedFieldCount: sealedFields.length, perRowKeysDestroyed: perRowKeysDestroyed };
279
328
  }
280
329
 
281
330
  function _cascade(rule, rowId, dryRun) {
@@ -284,15 +333,20 @@ function create(opts) {
284
333
  for (var i = 0; i < rule.cascade.length; i++) {
285
334
  var c = rule.cascade[i];
286
335
  if (dryRun) {
287
- var sel = db.prepare(
288
- "SELECT COUNT(*) AS n FROM \"" + c.table + "\" WHERE \"" + c.foreignKey + "\" = ?");
289
- var n = sel.get(rowId);
336
+ var selBuilt = sql.select(c.table, SQL_OPTS)
337
+ .count("*", "n")
338
+ .where(c.foreignKey, rowId)
339
+ .toSql();
340
+ var sel = db.prepare(selBuilt.sql);
341
+ var n = sel.get.apply(sel, selBuilt.params);
290
342
  cascadeSummary.push({ table: c.table, foreignKey: c.foreignKey,
291
343
  wouldDelete: (n && typeof n.n === "number") ? n.n : 0 });
292
344
  } else {
293
- var del = db.prepare(
294
- "DELETE FROM \"" + c.table + "\" WHERE \"" + c.foreignKey + "\" = ?");
295
- var result = del.run(rowId);
345
+ var delBuilt = sql.delete(c.table, SQL_OPTS)
346
+ .where(c.foreignKey, rowId)
347
+ .toSql();
348
+ var del = db.prepare(delBuilt.sql);
349
+ var result = del.run.apply(del, delBuilt.params);
296
350
  cascadeSummary.push({ table: c.table, foreignKey: c.foreignKey,
297
351
  deleted: result.changes || 0 });
298
352
  }
@@ -382,24 +436,31 @@ function create(opts) {
382
436
  while (moreRows) {
383
437
  var rows;
384
438
  // The candidate WHERE-clause: age + not-already-erased + not-on-legal-hold +
385
- // (when soft-delete is configured) not-already-soft-deleted.
386
- var whereParts = ['"' + rule.ageField + '" <= ?'];
387
- var whereArgs = [cutoff];
388
- if (rule.softDeleteField) {
389
- whereParts.push('("' + rule.softDeleteField + '" IS NULL)');
439
+ // (when soft-delete is configured) not-already-soft-deleted. Built
440
+ // through b.sql so the operator-supplied table / ageField / softDeleteField
441
+ // identifiers are quoted by construction and every value binds as a
442
+ // placeholder (the '' empty-string compare included — no embedded literal).
443
+ function _candidateBase() {
444
+ var qb = sql.select(rule.table, SQL_OPTS)
445
+ .where(rule.ageField, "<=", cutoff);
446
+ if (rule.softDeleteField) qb.whereNull(rule.softDeleteField);
447
+ return qb;
390
448
  }
391
- var sql = "SELECT * FROM \"" + rule.table + "\" " +
392
- "WHERE " + whereParts.join(" AND ") + " " +
393
- "AND (__erasedAt IS NULL OR __erasedAt = '') " +
394
- "LIMIT ?";
395
449
  var selStmt;
396
- try { selStmt = db.prepare(sql); rows = selStmt.all.apply(selStmt, whereArgs.concat([rule.batchSize])); }
397
- catch (_eA) {
450
+ try {
451
+ var built = _candidateBase()
452
+ .whereGroup(function (g) {
453
+ g.whereNull("__erasedAt").orWhereOp("__erasedAt", "=", "");
454
+ })
455
+ .limit(rule.batchSize)
456
+ .toSql();
457
+ selStmt = db.prepare(built.sql);
458
+ rows = selStmt.all.apply(selStmt, built.params);
459
+ } catch (_eA) {
398
460
  // Fallback: tables without __erasedAt
399
- var sqlPlain = "SELECT * FROM \"" + rule.table + "\" " +
400
- "WHERE " + whereParts.join(" AND ") + " LIMIT ?";
401
- var selPlain = db.prepare(sqlPlain);
402
- rows = selPlain.all.apply(selPlain, whereArgs.concat([rule.batchSize]));
461
+ var plainBuilt = _candidateBase().limit(rule.batchSize).toSql();
462
+ var selPlain = db.prepare(plainBuilt.sql);
463
+ rows = selPlain.all.apply(selPlain, plainBuilt.params);
403
464
  }
404
465
  if (!rows || rows.length === 0) { moreRows = false; break; }
405
466
  summary.scanned += rows.length;
@@ -42,6 +42,7 @@ var lazyRequire = require("./lazy-require");
42
42
  var safeAsync = require("./safe-async");
43
43
  var safeEnv = require("./parsers/safe-env");
44
44
  var safeUrl = require("./safe-url");
45
+ var validateOpts = require("./validate-opts");
45
46
  var websocket = require("./websocket");
46
47
  var { boot } = require("./log");
47
48
  var { RouterError } = require("./framework-error");
@@ -301,6 +302,13 @@ class Router {
301
302
  constructor(opts) {
302
303
  opts = opts || {};
303
304
  this.routes = [];
305
+ // Registration-ordered middleware table. Each entry is
306
+ // `{ prefix, prefixSegments, fn }`: `prefix === null` is a global
307
+ // middleware (runs on every request); a non-null `prefix` is a
308
+ // path-scoped middleware that runs only when the request path
309
+ // matches the prefix on segment boundaries. Path-scoped and global
310
+ // entries interleave in registration order so a gate registered
311
+ // before a route still runs before it.
304
312
  this.middleware = [];
305
313
  // WebSocket routes are kept separate from HTTP routes — they're
306
314
  // matched on the upgrade / Extended CONNECT nodePath, not on a method
@@ -453,8 +461,23 @@ class Router {
453
461
  return conns.length;
454
462
  }
455
463
 
456
- use(fn) {
457
- this.middleware.push(fn);
464
+ // use(mw) global middleware (runs on every request)
465
+ // use(mw1, mw2, ...) — several global middlewares, in order
466
+ // use(prefix, mw1, mw2, ...) — path-scoped: mw runs only when the
467
+ // request path is at or beneath `prefix`
468
+ // on segment boundaries ("/admin" covers
469
+ // "/admin" + "/admin/x", not "/administrator")
470
+ // use([prefixA, prefixB], mw) — scoped to any of several prefixes
471
+ //
472
+ // Bad input throws at config time (a non-string / non-array prefix, a
473
+ // prefix that doesn't begin with "/", a non-function middleware) so an
474
+ // operator wiring typo surfaces at boot instead of silently dropping a
475
+ // security gate or 500-ing every request.
476
+ use() {
477
+ var entries = _normalizeUseArgs(Array.prototype.slice.call(arguments));
478
+ for (var i = 0; i < entries.length; i++) {
479
+ this.middleware.push(entries[i]);
480
+ }
458
481
  }
459
482
 
460
483
  // Internal: split a route registration's args into { spec, handlers }.
@@ -687,8 +710,24 @@ class Router {
687
710
  }
688
711
  req.query = Object.fromEntries(queryEntries);
689
712
 
690
- // Run middleware
691
- for (var mw of this.middleware) {
713
+ // Run middleware in registration order. Global entries
714
+ // (prefixSegmentsList === null) run on every request; path-scoped
715
+ // entries run only when req.pathname is at or beneath one of the
716
+ // mount's prefixes (segment-boundary match). A skipped scoped
717
+ // middleware does NOT short-circuit the chain — the next entry
718
+ // still runs.
719
+ for (var entry of this.middleware) {
720
+ if (entry.prefixSegmentsList !== null) {
721
+ var matched = false;
722
+ for (var pli = 0; pli < entry.prefixSegmentsList.length; pli++) {
723
+ if (_pathMatchesPrefix(entry.prefixSegmentsList[pli], req.pathname)) {
724
+ matched = true;
725
+ break;
726
+ }
727
+ }
728
+ if (!matched) continue;
729
+ }
730
+ var mw = entry.fn;
692
731
  var next = false;
693
732
  try {
694
733
  await mw(req, res, () => (next = true));
@@ -1206,6 +1245,152 @@ class Router {
1206
1245
  }
1207
1246
  }
1208
1247
 
1248
+ // ---- Path-scoped `use()` helpers ----
1249
+ //
1250
+ // These back `Router.use(prefix, mw)`. They live after the class
1251
+ // (hoisted function declarations are visible to the methods regardless
1252
+ // of source order) so the class methods sit contiguous with the
1253
+ // route-matching helpers above.
1254
+
1255
+ // Compile a `use(prefix, mw)` path prefix into the segment list the
1256
+ // matcher walks. A prefix is the literal-segment portion of a path
1257
+ // ("/admin", "/.well-known/jmap") — parameter segments (":id") are not
1258
+ // meaningful for a mounting prefix, so they're treated as literals.
1259
+ //
1260
+ // Normalization mirrors route-pattern handling: split on "/" and drop a
1261
+ // single trailing-slash artifact so "/admin" and "/admin/" mount the
1262
+ // same. The leading empty segment from the leading "/" is preserved so
1263
+ // the prefix anchors at the path root (a prefix that does not begin with
1264
+ // "/" is refused at the use() entry point).
1265
+ function _compilePrefix(prefix) {
1266
+ var segments = prefix.split("/");
1267
+ // A trailing "/" produces a final empty segment ("/admin/" → ["", "admin", ""]).
1268
+ // Drop it so the trailing slash doesn't force an extra path segment.
1269
+ if (segments.length > 1 && segments[segments.length - 1] === "") {
1270
+ segments.pop();
1271
+ }
1272
+ return segments;
1273
+ }
1274
+
1275
+ // True when `pathname` is at or beneath the mounting prefix, matching on
1276
+ // segment boundaries. "/admin" matches "/admin" and "/admin/x" but NOT
1277
+ // "/administrator" (Express-style segment semantics) — a substring
1278
+ // prefix that lands mid-segment is a no-match so a security gate scoped
1279
+ // to "/admin" never leaks onto a sibling path that merely shares a
1280
+ // textual prefix.
1281
+ function _pathMatchesPrefix(prefixSegments, pathname) {
1282
+ var pathSegments = pathname.split("/");
1283
+ if (pathSegments.length < prefixSegments.length) return false;
1284
+ // Compare segment-for-segment. This is routing metadata (public URL
1285
+ // path), not secret material, so an ordinary equality walk is correct
1286
+ // — no constant-time comparison is warranted.
1287
+ return prefixSegments.every(function (seg, i) {
1288
+ return pathSegments[i] === seg;
1289
+ });
1290
+ }
1291
+
1292
+ // Classify the first `use()` argument:
1293
+ // function → global mount (prefixes stays null)
1294
+ // string / string[] → path-scoped mount (one or more prefixes)
1295
+ // anything else → operator wiring typo, refused at config time
1296
+ // Returns the prefix array (or null for a global mount). Does not touch
1297
+ // the middleware functions — the caller validates those.
1298
+ function _usePrefixesFromFirstArg(first) {
1299
+ if (typeof first === "function") return null;
1300
+ if (typeof first !== "string" && !Array.isArray(first)) {
1301
+ throw new RouterError("router/use-bad-first-arg",
1302
+ "router.use: first argument must be a middleware function, a path " +
1303
+ "prefix string, or an array of prefix strings (got " +
1304
+ (first === null ? "null" : typeof first) + ")");
1305
+ }
1306
+ var prefixes = Array.isArray(first) ? first : [first];
1307
+ if (prefixes.length === 0) {
1308
+ throw new RouterError("router/use-empty-prefix-array",
1309
+ "router.use: path-prefix array must contain at least one prefix string");
1310
+ }
1311
+ // Array-of-non-empty-strings shape (the index-pointing throw on a
1312
+ // non-string / empty entry) is the shared validate-opts contract.
1313
+ validateOpts.optionalNonEmptyStringArray(
1314
+ prefixes, "router.use: path prefix", RouterError, "router/use-prefix-not-string");
1315
+ // Prefix-specific grammar: anchor at "/" + bounded length.
1316
+ for (var i = 0; i < prefixes.length; i++) {
1317
+ var grammarErr = _prefixGrammarError(prefixes[i]);
1318
+ if (grammarErr) throw grammarErr;
1319
+ }
1320
+ return prefixes;
1321
+ }
1322
+
1323
+ // Return a RouterError describing why `prefix` is not a valid mounting
1324
+ // prefix, or null when it is valid. Split out so the per-prefix grammar
1325
+ // check is one branch, not an inline throw-block in the loop.
1326
+ function _prefixGrammarError(prefix) {
1327
+ if (prefix.charAt(0) !== "/") {
1328
+ return new RouterError("router/use-prefix-not-absolute",
1329
+ "router.use: path prefix '" + prefix + "' must begin with '/'");
1330
+ }
1331
+ if (prefix.length > MAX_ROUTE_PATTERN_LEN) {
1332
+ return new RouterError("router/use-prefix-too-long",
1333
+ "router.use: path prefix exceeds " + MAX_ROUTE_PATTERN_LEN +
1334
+ " chars (got " + prefix.length + ")");
1335
+ }
1336
+ return null;
1337
+ }
1338
+
1339
+ // Index of the first non-function entry in `fns`, or -1 when all are
1340
+ // functions. Kept separate so the middleware-shape check is a scan, not
1341
+ // an inline throw inside the normalize flow.
1342
+ function _firstNonFunctionIndex(fns) {
1343
+ for (var i = 0; i < fns.length; i++) {
1344
+ if (typeof fns[i] !== "function") return i;
1345
+ }
1346
+ return -1;
1347
+ }
1348
+
1349
+ // Validate + normalize the `use()` arguments into middleware-table
1350
+ // entries. Config-time entry-point tier: a non-string / non-array-of-
1351
+ // strings prefix or a non-function middleware is an operator wiring
1352
+ // typo and throws so it surfaces at boot, not as a silent dropped gate
1353
+ // or a request-time 500. Returns one entry per middleware function:
1354
+ // { prefix: null, prefixSegmentsList: null, fn } — global
1355
+ // { prefix: "/admin", prefixSegmentsList: [[...], ...], fn } — scoped
1356
+ // A scoped entry matches when ANY of its prefixes match the request
1357
+ // path on segment boundaries; the fn runs at most once per request even
1358
+ // when two of its prefixes both match (nested prefixes), so a gate never
1359
+ // double-executes.
1360
+ function _normalizeUseArgs(args) {
1361
+ if (args.length === 0) {
1362
+ throw new RouterError("router/use-no-args",
1363
+ "router.use: requires at least one middleware function");
1364
+ }
1365
+ var prefixes = _usePrefixesFromFirstArg(args[0]);
1366
+ // Global mount uses every arg as a middleware; a scoped mount drops the
1367
+ // leading prefix arg and uses the rest.
1368
+ var fns = (prefixes === null) ? args : args.slice(1);
1369
+ if (fns.length === 0) {
1370
+ throw new RouterError("router/use-no-middleware",
1371
+ "router.use: path-scoped mount requires at least one middleware " +
1372
+ "function after the prefix");
1373
+ }
1374
+ var nonFn = _firstNonFunctionIndex(fns);
1375
+ if (nonFn !== -1) {
1376
+ throw new RouterError("router/use-middleware-not-function",
1377
+ "router.use: middleware at position " + nonFn +
1378
+ " must be a function (got " +
1379
+ (fns[nonFn] === null ? "null" : typeof fns[nonFn]) + ")");
1380
+ }
1381
+ // Pre-compile each prefix to its segment list once at registration so
1382
+ // dispatch only walks segments, never re-splits the prefix per request.
1383
+ var segmentsList = (prefixes === null) ? null : prefixes.map(_compilePrefix);
1384
+ var label = (prefixes === null) ? null
1385
+ : (prefixes.length === 1 ? prefixes[0] : prefixes.slice());
1386
+ // One entry per fn, preserving the order each middleware was passed —
1387
+ // a path-scoped mount with two middlewares interleaves them in
1388
+ // registration order just like two separate use() calls would.
1389
+ return fns.map(function (fn) {
1390
+ return { prefix: label, prefixSegmentsList: segmentsList, fn: fn };
1391
+ });
1392
+ }
1393
+
1209
1394
  /**
1210
1395
  * @primitive b.router.serveStatic
1211
1396
  * @signature b.router.serveStatic(dir)
@@ -1266,7 +1451,7 @@ function serveStatic(dir) {
1266
1451
  *
1267
1452
  * Builds a `Router` instance with the framework's security-on-by-
1268
1453
  * default posture. Returned object exposes `get / post / put / patch
1269
- * / delete` for route registration, `use(fn)` for global middleware,
1454
+ * / delete` for route registration, `use(...)` for middleware,
1270
1455
  * `ws(path, handler, opts?)` for WebSocket routes, `onNotFound(fn)`
1271
1456
  * and `onError(fn)` for fallthrough hooks, `inspectRoutes()` and
1272
1457
  * `openapi()` for introspection, `closeWebSockets({ timeoutMs })`
@@ -1274,6 +1459,21 @@ function serveStatic(dir) {
1274
1459
  * which boots an HTTP/2-capable TLS server (ALPN h2 + http/1.1) when
1275
1460
  * `tlsOptions` is provided, an HTTP/1.1 server otherwise.
1276
1461
  *
1462
+ * `use` has two forms. `use(mw)` (and `use(mw1, mw2, ...)`) mounts
1463
+ * global middleware that runs on every request. `use(prefix, mw1,
1464
+ * mw2, ...)` mounts path-scoped middleware that runs only when the
1465
+ * request path is at or beneath `prefix`, matched on segment
1466
+ * boundaries — `"/admin"` covers `"/admin"` and `"/admin/x"` but not
1467
+ * `"/administrator"`. The prefix may be an array of strings to scope a
1468
+ * gate to several path roots at once. Global and scoped middleware
1469
+ * interleave in registration order, so a gate registered before a
1470
+ * route still runs before it. A non-string / non-array prefix, a
1471
+ * prefix not beginning with `"/"`, or a non-function middleware throws
1472
+ * at registration time rather than dropping the gate or 500-ing every
1473
+ * request — scope a security middleware (`csrf`, `bearerAuth`,
1474
+ * `requireAal`, `requireMtls`) to a path with confidence it runs
1475
+ * exactly where mounted.
1476
+ *
1277
1477
  * @opts
1278
1478
  * tls0Rtt: "refuse" | "replay-cache", // RFC 8446 §8 anti-replay; default "refuse"
1279
1479
  * allowedRedirectOrigins: string[], // exact-match HTTPS origins for cross-origin res.redirect()
@@ -1286,6 +1486,13 @@ function serveStatic(dir) {
1286
1486
  * router.get("/users/:id", function (req, res) {
1287
1487
  * res.json({ id: req.params.id });
1288
1488
  * });
1489
+ *
1490
+ * // Global middleware — runs on every request.
1491
+ * router.use(b.middleware.securityHeaders());
1492
+ *
1493
+ * // Path-scoped middleware — the step-up gate runs only under /admin.
1494
+ * router.use("/admin", b.middleware.requireAal({ minimum: "AAL2" }));
1495
+ *
1289
1496
  * router.listen(3000);
1290
1497
  */
1291
1498
  function create(opts) {
@@ -57,6 +57,7 @@
57
57
 
58
58
  var C = require("./constants");
59
59
  var { defineClass } = require("./framework-error");
60
+ var gateContract = require("./gate-contract");
60
61
 
61
62
  var SafeDnsError = defineClass("SafeDnsError", { alwaysPermanent: true });
62
63
 
@@ -153,11 +154,15 @@ var PROFILES = Object.freeze({
153
154
  },
154
155
  });
155
156
 
156
- var COMPLIANCE_POSTURES = Object.freeze({
157
- hipaa: "strict",
158
- "pci-dss": "strict",
159
- gdpr: "strict",
160
- soc2: "strict",
157
+ var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
158
+
159
+ var _resolveProfile = gateContract.makeProfileResolver({
160
+ profiles: PROFILES,
161
+ postures: COMPLIANCE_POSTURES,
162
+ defaults: DEFAULT_PROFILE,
163
+ errorClass: SafeDnsError,
164
+ codePrefix: "safe-dns",
165
+ byObject: true,
161
166
  });
162
167
 
163
168
  /**
@@ -349,22 +354,6 @@ function checkCnameChainDepth(depth, opts) {
349
354
  }
350
355
  }
351
356
 
352
- /**
353
- * @primitive b.safeDns.compliancePosture
354
- * @signature b.safeDns.compliancePosture(posture)
355
- * @since 0.9.31
356
- * @status stable
357
- *
358
- * Return the effective profile name for a compliance posture, or
359
- * `null` for unknown posture names (operator typo surfaces here).
360
- *
361
- * @example
362
- * b.safeDns.compliancePosture("hipaa"); // → "strict"
363
- */
364
- function compliancePosture(posture) {
365
- return COMPLIANCE_POSTURES[posture] || null;
366
- }
367
-
368
357
  function _readName(state, pointerDepth) {
369
358
  if (pointerDepth > state.caps.maxPointerDepth) {
370
359
  throw new SafeDnsError("safe-dns/oversize-pointer-depth",
@@ -639,27 +628,22 @@ function _decodeOpt(rr, caps) {
639
628
  };
640
629
  }
641
630
 
642
- function _resolveProfile(opts) {
643
- if (opts.posture && COMPLIANCE_POSTURES[opts.posture]) {
644
- return PROFILES[COMPLIANCE_POSTURES[opts.posture]];
645
- }
646
- var p = opts.profile || DEFAULT_PROFILE;
647
- if (!PROFILES[p]) {
648
- throw new SafeDnsError("safe-dns/bad-profile",
649
- "safeDns: unknown profile '" + p + "' (valid: strict / balanced / permissive)");
650
- }
651
- return PROFILES[p];
652
- }
653
-
654
- module.exports = {
655
- parseResponse: parseResponse,
656
- boundEdns0: boundEdns0,
657
- checkCnameChainDepth: checkCnameChainDepth,
658
- compliancePosture: compliancePosture,
659
- PROFILES: PROFILES,
660
- COMPLIANCE_POSTURES: COMPLIANCE_POSTURES,
661
- RTYPE_NAMES: RTYPE_NAMES,
662
- SafeDnsError: SafeDnsError,
663
- NAME: "dns",
664
- KIND: "dns-response",
665
- };
631
+ // compliancePosture is assembled by gateContract.defineParser below; its
632
+ // wiki section renders from the single-sourced @abiTemplate (defineParser)
633
+ // block in gate-contract.js, instantiated for this guard by the page
634
+ // generator.
635
+ module.exports = gateContract.defineParser({
636
+ name: "dns",
637
+ entry: parseResponse,
638
+ entryName: "parseResponse",
639
+ errorClass: SafeDnsError,
640
+ profiles: PROFILES,
641
+ postures: COMPLIANCE_POSTURES,
642
+ extra: {
643
+ boundEdns0: boundEdns0,
644
+ checkCnameChainDepth: checkCnameChainDepth,
645
+ RTYPE_NAMES: RTYPE_NAMES,
646
+ NAME: "dns",
647
+ KIND: "dns-response",
648
+ },
649
+ });
@@ -81,6 +81,7 @@
81
81
 
82
82
  var C = require("./constants");
83
83
  var { defineClass } = require("./framework-error");
84
+ var gateContract = require("./gate-contract");
84
85
 
85
86
  var SafeIcalError = defineClass("SafeIcalError", { alwaysPermanent: true });
86
87
 
@@ -116,12 +117,7 @@ var PROFILES = Object.freeze({
116
117
  }),
117
118
  });
118
119
 
119
- var COMPLIANCE_POSTURES = Object.freeze({
120
- hipaa: "strict",
121
- "pci-dss": "strict",
122
- gdpr: "strict",
123
- soc2: "strict",
124
- });
120
+ var COMPLIANCE_POSTURES = gateContract.ALL_STRICT_POSTURES;
125
121
 
126
122
  // Property-name allowlist per RFC 5545 §8.7 (Property Registry) +
127
123
  // RFC 5546 §4.3 (iTIP additions) + RFC 7986 §5 (new calendar
@@ -273,24 +269,6 @@ function parse(text, opts) {
273
269
  : { vcalendar: vcalendars[0], vcalendars: vcalendars };
274
270
  }
275
271
 
276
- /**
277
- * @primitive b.safeIcal.compliancePosture
278
- * @signature b.safeIcal.compliancePosture(name)
279
- * @since 0.9.81
280
- * @status stable
281
- * @related b.safeIcal.parse
282
- *
283
- * Map a compliance-posture name to its profile. Returns the profile
284
- * string for a known posture, `null` for unknown names.
285
- *
286
- * @example
287
- * b.safeIcal.compliancePosture("hipaa"); // → "strict"
288
- * b.safeIcal.compliancePosture("loose"); // → null
289
- */
290
- function compliancePosture(name) {
291
- return COMPLIANCE_POSTURES[name] || null;
292
- }
293
-
294
272
  // ---- Profile / opt resolution ----
295
273
 
296
274
  function _resolveCaps(opts) {
@@ -623,12 +601,19 @@ function _preview(s) {
623
601
  return s.length > 64 ? s.slice(0, 64) + "..." : s; // log-preview length cap
624
602
  }
625
603
 
626
- module.exports = {
627
- parse: parse,
628
- compliancePosture: compliancePosture,
629
- PROFILES: PROFILES,
630
- COMPLIANCE_POSTURES: COMPLIANCE_POSTURES,
631
- KNOWN_PROPERTIES: KNOWN_PROPERTIES,
632
- KNOWN_COMPONENTS: KNOWN_COMPONENTS,
633
- SafeIcalError: SafeIcalError,
634
- };
604
+ // compliancePosture is assembled by gateContract.defineParser below; its
605
+ // wiki section renders from the single-sourced @abiTemplate (defineParser)
606
+ // block in gate-contract.js, instantiated for this guard by the page
607
+ // generator.
608
+ module.exports = gateContract.defineParser({
609
+ name: "ical",
610
+ entry: parse,
611
+ entryName: "parse",
612
+ errorClass: SafeIcalError,
613
+ profiles: PROFILES,
614
+ postures: COMPLIANCE_POSTURES,
615
+ extra: {
616
+ KNOWN_PROPERTIES: KNOWN_PROPERTIES,
617
+ KNOWN_COMPONENTS: KNOWN_COMPONENTS,
618
+ },
619
+ });