@blamejs/blamejs-shop 0.4.31 → 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 (336) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/vendor/MANIFEST.json +392 -278
  4. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  5. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  6. package/lib/vendor/blamejs/.gitignore +6 -0
  7. package/lib/vendor/blamejs/CHANGELOG.md +26 -0
  8. package/lib/vendor/blamejs/MIGRATING.md +43 -0
  9. package/lib/vendor/blamejs/README.md +8 -6
  10. package/lib/vendor/blamejs/SECURITY.md +19 -3
  11. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  12. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  13. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  14. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  15. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  16. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  17. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  18. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  19. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  20. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  21. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  22. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  23. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  24. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  25. package/lib/vendor/blamejs/index.js +4 -0
  26. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  27. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  28. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  29. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  30. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  31. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  32. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  33. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  34. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  35. package/lib/vendor/blamejs/lib/audit.js +259 -123
  36. package/lib/vendor/blamejs/lib/auth/oauth.js +53 -9
  37. package/lib/vendor/blamejs/lib/auth/openid-federation.js +108 -47
  38. package/lib/vendor/blamejs/lib/auth/saml.js +6 -8
  39. package/lib/vendor/blamejs/lib/auth/sd-jwt-vc.js +31 -5
  40. package/lib/vendor/blamejs/lib/backup/index.js +45 -10
  41. package/lib/vendor/blamejs/lib/break-glass.js +355 -147
  42. package/lib/vendor/blamejs/lib/cache.js +174 -105
  43. package/lib/vendor/blamejs/lib/chain-writer.js +38 -16
  44. package/lib/vendor/blamejs/lib/cli.js +19 -14
  45. package/lib/vendor/blamejs/lib/cluster-provider-db.js +130 -104
  46. package/lib/vendor/blamejs/lib/cluster-storage.js +119 -22
  47. package/lib/vendor/blamejs/lib/cluster.js +119 -71
  48. package/lib/vendor/blamejs/lib/codepoint-class.js +23 -0
  49. package/lib/vendor/blamejs/lib/compliance.js +206 -4
  50. package/lib/vendor/blamejs/lib/consent.js +82 -29
  51. package/lib/vendor/blamejs/lib/constants.js +27 -11
  52. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  53. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  54. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  55. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  56. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  57. package/lib/vendor/blamejs/lib/db.js +249 -99
  58. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  59. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  60. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  61. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  62. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  63. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  64. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  65. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  66. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  67. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  68. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  69. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  70. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  71. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  72. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  73. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  74. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  75. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  76. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  77. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  78. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  79. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  80. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  81. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  82. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  83. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  84. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  85. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  86. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  87. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  88. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  89. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  90. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  91. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  92. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  93. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  94. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  95. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  96. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  97. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  98. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  99. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  100. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  101. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  102. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  103. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  104. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  105. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  106. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  107. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  108. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  109. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  110. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  111. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  112. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  113. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  114. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  115. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  116. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  117. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  118. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  119. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  120. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  121. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  122. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  123. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  124. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  125. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  126. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  127. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  128. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  129. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  131. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  132. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  133. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  134. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  135. package/lib/vendor/blamejs/lib/mail.js +8 -4
  136. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  137. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  138. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  139. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  140. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  141. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  142. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  143. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  144. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  145. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  146. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  147. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  148. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  149. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  150. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  151. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  152. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  153. package/lib/vendor/blamejs/lib/observability.js +124 -0
  154. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  155. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  156. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  157. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  158. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  159. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  160. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  161. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  162. package/lib/vendor/blamejs/lib/queue.js +7 -0
  163. package/lib/vendor/blamejs/lib/redact.js +68 -11
  164. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  165. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  166. package/lib/vendor/blamejs/lib/retention.js +101 -40
  167. package/lib/vendor/blamejs/lib/router.js +212 -5
  168. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  169. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  170. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  171. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  172. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  173. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  174. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  175. package/lib/vendor/blamejs/lib/scheduler.js +35 -12
  176. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  177. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  178. package/lib/vendor/blamejs/lib/session.js +175 -77
  179. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  180. package/lib/vendor/blamejs/lib/sse.js +26 -0
  181. package/lib/vendor/blamejs/lib/ssrf-guard.js +151 -4
  182. package/lib/vendor/blamejs/lib/static.js +177 -34
  183. package/lib/vendor/blamejs/lib/subject.js +96 -49
  184. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  185. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  186. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  187. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  188. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  189. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  190. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  191. package/lib/vendor/blamejs/package.json +2 -2
  192. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  193. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  194. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  195. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  200. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  201. package/lib/vendor/blamejs/scripts/gen-migrating.js +51 -0
  202. package/lib/vendor/blamejs/scripts/release.js +398 -38
  203. package/lib/vendor/blamejs/test/00-primitives.js +117 -0
  204. package/lib/vendor/blamejs/test/10-state.js +140 -14
  205. package/lib/vendor/blamejs/test/20-db.js +65 -2
  206. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  207. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  208. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  209. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  210. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  211. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  212. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  213. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  214. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  215. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  216. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  217. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  220. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  221. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  222. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  223. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  224. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  225. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  226. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  227. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  228. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  229. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  230. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  231. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  232. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  233. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  234. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  235. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  236. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  237. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  238. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  239. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  240. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  242. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  248. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1120 -14
  249. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  251. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  252. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  253. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  254. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  256. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  258. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  259. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  267. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  270. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  271. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  272. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  273. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  275. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  276. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  277. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  278. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  281. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  282. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  283. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  286. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  287. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  288. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  291. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  296. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +309 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  302. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  308. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  309. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  310. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  311. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  312. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  313. package/lib/vendor/blamejs/test/smoke.js +79 -21
  314. package/package.json +1 -1
  315. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  316. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  317. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  318. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  319. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  320. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  321. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  322. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  323. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  324. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  325. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  326. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  327. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  328. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  329. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  330. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  331. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  332. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  333. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  334. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  335. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  336. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -1833,10 +1833,30 @@ function create(opts) {
1833
1833
  var now = Math.floor(Date.now() / C.TIME.seconds(1));
1834
1834
  var skewSec = Math.floor(clockSkewMs / C.TIME.seconds(1));
1835
1835
  // OIDC Back-Channel Logout 1.0 §2.4 — logout tokens have no `exp`
1836
- // claim; freshness comes from `iat` + jti-replay window. Operators
1837
- // verifying logout tokens pass `skipExpCheck: true`. ID tokens
1838
- // never set this and continue to require `exp`.
1839
- if (!vopts.skipExpCheck) {
1836
+ // claim; freshness comes from `iat` + jti-replay window. `skipExpCheck`
1837
+ // bypasses the exp gate for that path ONLY. It is a public-API option,
1838
+ // so it must be self-guarding: refuse it on any token that is not a
1839
+ // logout token (no back-channel-logout event), or a caller could verify
1840
+ // an expired/replayed id_token clean. Logout tokens then carry no exp,
1841
+ // so `iat` is the only freshness bound — enforce a max-age floor.
1842
+ if (vopts.skipExpCheck) {
1843
+ if (!payload.events || typeof payload.events !== "object" ||
1844
+ !payload.events["http://schemas.openid.net/event/backchannel-logout"]) {
1845
+ throw new OAuthError("auth-oauth/skip-exp-check-not-allowed",
1846
+ "skipExpCheck is only valid for back-channel-logout tokens " +
1847
+ "(OIDC Back-Channel Logout 1.0 §2.4); this token carries no logout event claim");
1848
+ }
1849
+ // Honor the operator's configured replay window. verifyBackchannelLogoutToken
1850
+ // exposes vopts.maxAgeSec (default 5 min) and passes it through here; a
1851
+ // deployment that widened the window must not have this freshness floor
1852
+ // reject a token between the default and its configured max age.
1853
+ var logoutMaxAgeSec = (typeof vopts.maxAgeSec === "number" && isFinite(vopts.maxAgeSec) &&
1854
+ vopts.maxAgeSec > 0) ? vopts.maxAgeSec : DEFAULT_LOGOUT_TOKEN_MAX_AGE_SEC;
1855
+ if (typeof payload.iat !== "number" || payload.iat + logoutMaxAgeSec + skewSec < now) {
1856
+ throw new OAuthError("auth-oauth/logout-token-stale",
1857
+ "logout token iat is older than " + logoutMaxAgeSec + "s (no exp; iat is the freshness bound)");
1858
+ }
1859
+ } else {
1840
1860
  if (typeof payload.exp !== "number" || payload.exp + skewSec < now) {
1841
1861
  throw new OAuthError("auth-oauth/expired", "ID token expired (exp=" + payload.exp + ", now=" + now + ")");
1842
1862
  }
@@ -2016,13 +2036,19 @@ function create(opts) {
2016
2036
  if (uopts.prompt) authzParams.prompt = uopts.prompt;
2017
2037
  if (uopts.loginHint) authzParams.login_hint = uopts.loginHint;
2018
2038
  if (uopts.maxAge != null) authzParams.max_age = String(uopts.maxAge);
2019
- // RFC 9396 — push the fine-grained authorization request through PAR
2020
- // identically to the redirect path (validated, then JSON-serialized).
2039
+ // RFC 9396 — push the fine-grained authorization request through PAR.
2040
+ // On the plain-form branch the value is a form parameter (JSON STRING);
2041
+ // on the signed-request-object branch it becomes a JAR claim and MUST
2042
+ // be the native JSON ARRAY (RFC 9101/9396) — a conforming AS rejects a
2043
+ // string-valued authorization_details claim. Carry the validated array
2044
+ // and serialize ONLY when it travels as a form param.
2021
2045
  var requestedAuthzDetails = null;
2022
2046
  if (uopts.authorizationDetails !== undefined) {
2023
2047
  requestedAuthzDetails = _validateAuthorizationDetailsArray(
2024
2048
  uopts.authorizationDetails, "pushAuthorizationRequest");
2025
- authzParams.authorization_details = JSON.stringify(requestedAuthzDetails);
2049
+ authzParams.authorization_details = sro
2050
+ ? requestedAuthzDetails // JAR claim — native array
2051
+ : JSON.stringify(requestedAuthzDetails); // form param — JSON string
2026
2052
  }
2027
2053
  if (uopts.extraParams && typeof uopts.extraParams === "object") {
2028
2054
  var ek = Object.keys(uopts.extraParams);
@@ -2160,9 +2186,18 @@ function create(opts) {
2160
2186
  // store — operators wire b.cache or b.db.
2161
2187
  async function verifyBackchannelLogoutToken(logoutToken, vopts) {
2162
2188
  vopts = vopts || {};
2163
- if (typeof logoutToken !== "string" || logoutToken.length === 0) {
2189
+ // Type / non-empty / length-cap gate, folded into one bounds check.
2190
+ // The cap runs BEFORE the split + base64url decode — an attacker-
2191
+ // reachable endpoint can POST an arbitrarily large logout_token, and
2192
+ // bounding it first stops the decode from allocating unbounded memory.
2193
+ var logoutTokenIsString = typeof logoutToken === "string";
2194
+ if (!logoutTokenIsString || logoutToken.length === 0) {
2164
2195
  throw new OAuthError("auth-oauth/bad-logout-token",
2165
2196
  "verifyBackchannelLogoutToken: logoutToken must be a non-empty string");
2197
+ } else if (logoutToken.length > OAUTH_MAX_RESPONSE_BYTES) {
2198
+ throw new OAuthError("auth-oauth/logout-token-too-large",
2199
+ "verifyBackchannelLogoutToken: logout_token exceeds " +
2200
+ OAUTH_MAX_RESPONSE_BYTES + " bytes");
2166
2201
  }
2167
2202
  var parts = logoutToken.split(".");
2168
2203
  if (parts.length !== 3) {
@@ -2170,7 +2205,12 @@ function create(opts) {
2170
2205
  "verifyBackchannelLogoutToken: logout_token must be a 3-segment JWS");
2171
2206
  }
2172
2207
  var headerObj;
2173
- try { headerObj = JSON.parse(Buffer.from(parts[0], "base64url").toString("utf8")); } // allow:bare-json-parse pre-verify header parse to look up the typ; the JWS signature is verified by verifyIdToken below
2208
+ // Route the pre-verify header parse through safeJson (size-bounded) like
2209
+ // the in-module id_token / JWS-header siblings — the bare JSON.parse on
2210
+ // an attacker-reachable, not-yet-signature-checked header was the one
2211
+ // unbounded parse on this surface. The JWS signature is verified by
2212
+ // verifyIdToken below.
2213
+ try { headerObj = safeJson.parse(_b64urlDecode(parts[0]).toString("utf8"), { maxBytes: OAUTH_MAX_RESPONSE_BYTES }); }
2174
2214
  catch (_e) {
2175
2215
  throw new OAuthError("auth-oauth/bad-logout-header",
2176
2216
  "verifyBackchannelLogoutToken: malformed header");
@@ -2192,6 +2232,10 @@ function create(opts) {
2192
2232
  // Logout tokens have no exp claim per OIDC Back-Channel Logout
2193
2233
  // §2.4 — the freshness gate is iat + jti-replay window.
2194
2234
  skipExpCheck: true,
2235
+ // Pass the operator's configured replay window through so verifyIdToken's
2236
+ // iat freshness floor uses it, not the 5-min default (the wrapper's own
2237
+ // maxAgeSec check below stays as a belt-and-suspenders bound).
2238
+ maxAgeSec: vopts.maxAgeSec,
2195
2239
  });
2196
2240
  var claims = verified.claims;
2197
2241
 
@@ -334,14 +334,23 @@ function _applyOnePolicy(metadata, policy) {
334
334
  * @signature b.auth.openidFederation.applyMetadataPolicy(metadata, chain, kind)
335
335
  * @since 0.8.62
336
336
  *
337
- * Apply every metadata_policy in the chain (top-down) to the leaf's
337
+ * Apply the federation's metadata_policy (top-down) to the leaf's
338
338
  * declared metadata for the given entity-kind ("openid_relying_party"
339
339
  * / "openid_provider" / "federation_entity" / etc.) and return the
340
340
  * effective metadata. Throws on any policy violation.
341
341
  *
342
- * The chain is leaf-first; we reverse for top-down application so
343
- * the trust anchor's policy applies first, then each intermediate's,
344
- * then the leaf's claimed metadata is the starting object.
342
+ * Per OpenID Federation 1.0 §6.2, an entity's metadata_policy comes
343
+ * from the SUPERIOR-SIGNED subordinate statement about that entity
344
+ * (`chain[i].subordinate.metadata_policy`), NOT from the entity's own
345
+ * self-published configuration. An entity cannot self-declare the
346
+ * policy that constrains it — that would let a leaf widen or drop the
347
+ * trust anchor's value / subset_of / essential constraints. The leaf's
348
+ * own self-config metadata_policy is therefore ignored.
349
+ *
350
+ * The chain is leaf-first; each `chain[i].subordinate` is the statement
351
+ * signed by the superior directly above entity `i`, so walking high
352
+ * index → low index applies the anchor's policy first, then each
353
+ * intermediate's, narrowing down to the leaf (§6.2 narrow-only merge).
345
354
  *
346
355
  * @example
347
356
  * var effective = b.auth.openidFederation.applyMetadataPolicy(
@@ -361,12 +370,17 @@ function applyMetadataPolicy(metadata, chain, kind) {
361
370
  "applyMetadataPolicy: chain must be an array");
362
371
  }
363
372
  var out = Object.assign({}, metadata);
364
- // Walk top-down (anchor last in leaf-first array).
373
+ // Walk top-down (anchor last in leaf-first array). Read the policy
374
+ // from each node's SUPERIOR-SIGNED subordinate statement — never from
375
+ // the entity's own self-config — so the anchor/intermediate
376
+ // constraints can't be dropped by a self-declared policy. The anchor
377
+ // node carries no `.subordinate` (it terminates the chain) and is
378
+ // skipped; the leaf's self-config policy is never read.
365
379
  for (var i = chain.length - 1; i >= 0; i--) {
366
380
  var stmt = chain[i];
367
- if (!stmt || !stmt.claims) continue;
368
- if (stmt.claims.metadata_policy && stmt.claims.metadata_policy[kind]) {
369
- out = _applyOnePolicy(out, stmt.claims.metadata_policy[kind]);
381
+ if (!stmt || !stmt.subordinate) continue;
382
+ if (stmt.subordinate.metadata_policy && stmt.subordinate.metadata_policy[kind]) {
383
+ out = _applyOnePolicy(out, stmt.subordinate.metadata_policy[kind]);
370
384
  }
371
385
  }
372
386
  return out;
@@ -433,6 +447,18 @@ async function buildTrustChain(opts) {
433
447
  };
434
448
  var maxDepth = opts.maxDepth || MAX_CHAIN_DEPTH;
435
449
 
450
+ // ---- Phase 1: collect the chain bottom-up (leaf → anchor) ----------
451
+ // Fetch each entity's self-config + the superior-signed subordinate
452
+ // statement about it, but DEFER cryptographic chain verification to
453
+ // Phase 2. The signature on a subordinate statement must be checked
454
+ // against the keys ATTESTED for the signing authority by ITS superior
455
+ // — flowing down from the operator-pinned anchor — not against the
456
+ // authority's own self-published config jwks. Verifying eagerly here
457
+ // (against self-published keys) is a fetch-time TOCTOU: an attacker
458
+ // controlling the authority's endpoint can serve attacker jwks to the
459
+ // statement-verify fetch while serving genuine config elsewhere, and
460
+ // the only operator-pinned trust (the anchor key) never gates the
461
+ // subordinate links.
436
462
  var chain = [];
437
463
  var current = opts.leafEntityId;
438
464
  var depth = 0;
@@ -446,6 +472,7 @@ async function buildTrustChain(opts) {
446
472
  // hostile-federation probes immediately.
447
473
  var visited = Object.create(null);
448
474
  visited[current] = true;
475
+ var reachedAnchor = false;
449
476
  while (depth < maxDepth) {
450
477
  var entityConfigUrl = current.replace(/\/$/, "") + "/.well-known/openid-federation";
451
478
  var entityConfigJwt = await fetcher(entityConfigUrl);
@@ -454,21 +481,22 @@ async function buildTrustChain(opts) {
454
481
  throw new AuthError("auth-openid-federation/bad-self-statement",
455
482
  "entity configuration for \"" + current + "\" must have iss==sub==entity_id");
456
483
  }
457
- // Self-signed: verify with its own jwks.
484
+ // Self-statement integrity: a well-formed entity config is self-signed
485
+ // over its own jwks. This proves the document isn't truncated/garbled
486
+ // — it is NOT the trust decision. Trust flows from the anchor through
487
+ // the subordinate statements verified top-down in Phase 2.
458
488
  verifyEntityStatement(entityConfigJwt, parsedEC.claims.jwks || {});
459
489
 
460
490
  // Is this entity a trust anchor?
461
491
  if (Object.prototype.hasOwnProperty.call(opts.trustAnchors, current)) {
462
492
  // Verify the anchor's self-statement using the operator-pinned
463
493
  // JWKS — defends against a compromised anchor key by trusting
464
- // the configured one over what the anchor publishes today.
494
+ // the configured one over what the anchor publishes today. The
495
+ // pinned keys become the root of the top-down verification.
465
496
  verifyEntityStatement(entityConfigJwt, opts.trustAnchors[current]);
466
497
  chain.push({ jwt: entityConfigJwt, claims: parsedEC.claims, role: "trust_anchor" });
467
- _emitAudit("chain_built", "success", {
468
- leaf: opts.leafEntityId, depth: chain.length, anchor: current,
469
- });
470
- _emitMetric("chain-built");
471
- return chain;
498
+ reachedAnchor = true;
499
+ break;
472
500
  }
473
501
  // Not the anchor — add to chain, ascend via authority_hints.
474
502
  chain.push({
@@ -481,16 +509,15 @@ async function buildTrustChain(opts) {
481
509
  throw new AuthError("auth-openid-federation/no-authority-hints",
482
510
  "entity \"" + current + "\" has no authority_hints; cannot ascend to a trust anchor");
483
511
  }
484
- // Pick the FIRST authority_hint that resolves to a trust anchor,
485
- // OR the first that returns a valid subordinate statement. Real
486
- // operators with multiple federations usually have one anchor
487
- // active; we walk in order and pick the first success.
488
- // Track every per-authority failure reason and surface them on
489
- // `no-ascent` rather than masking silently
490
- // swallowing `catch (_e) {}` lets a hostile intermediate that
491
- // serves a malformed-then-valid pair shape-walk the verifier.
492
- // We continue past 404 / fetch errors but refuse on
493
- // signature-verify failure (cryptographic refusal is a hard stop).
512
+ // Pick the FIRST authority_hint that yields a fetchable subordinate
513
+ // statement with matching iss/sub. We continue past 404 / fetch /
514
+ // parse errors (acceptable "try the next hint") and surface every
515
+ // failure reason on `no-ascent` rather than masking it silently
516
+ // swallowing `catch (_e) {}` lets a hostile intermediate that serves
517
+ // a malformed-then-valid pair shape-walk the verifier. Cryptographic
518
+ // verification is NOT done here; the selected statement is verified
519
+ // against the superior-attested keys in Phase 2, so a forged
520
+ // signature fails the whole chain regardless of which hint picked it.
494
521
  var ascended = false;
495
522
  var ascentErrors = [];
496
523
  for (var ai = 0; ai < parsedEC.claims.authority_hints.length; ai++) {
@@ -502,49 +529,83 @@ async function buildTrustChain(opts) {
502
529
  ascentErrors.push({ authority: authority, code: "iss-sub-mismatch" });
503
530
  continue;
504
531
  }
505
- var authorityCfgJwt = await fetcher(authority.replace(/\/$/, "") + "/.well-known/openid-federation");
506
- var authorityCfgClaims = parseEntityStatement(authorityCfgJwt).claims;
507
- // Cryptographic verification — any throw here is a hard
508
- // refusal, NOT a "try next authority" signal. A malformed-
509
- // signature subordinate from an authority listed by the
510
- // entity means that authority is hostile or compromised;
511
- // moving on lets a chain-shaping attacker bypass the gate.
512
- verifyEntityStatement(subordinateJwt, authorityCfgClaims.jwks || {});
513
- chain[chain.length - 1].claims.jwks = parsedSub.claims.jwks || chain[chain.length - 1].claims.jwks;
514
- chain[chain.length - 1].subordinateJwt = subordinateJwt;
515
- chain[chain.length - 1].subordinate = parsedSub.claims;
516
- // Refuse revisit. A trust anchor terminates the loop
517
- // before re-entry, so a revisit here ALWAYS means a cyclic
532
+ // Refuse revisit. A trust anchor terminates the loop before
533
+ // re-entry, so a revisit here ALWAYS means a cyclic
518
534
  // authority_hints graph.
519
535
  if (visited[authority]) {
520
536
  throw new AuthError("auth-openid-federation/chain-cycle",
521
537
  "buildTrustChain: authority \"" + authority + "\" already visited — " +
522
538
  "cyclic authority_hints graph refused");
523
539
  }
540
+ // Stash the superior-signed subordinate statement on the entity
541
+ // it is ABOUT. Phase 2 verifies its signature against the
542
+ // attested keys for `authority` and applies its metadata_policy.
543
+ chain[chain.length - 1].subordinateJwt = subordinateJwt;
544
+ chain[chain.length - 1].subordinate = parsedSub.claims;
524
545
  visited[authority] = true;
525
546
  current = authority;
526
547
  ascended = true;
527
548
  break;
528
549
  } catch (err) {
550
+ // A cycle refusal is a hard stop, not a "try next hint" signal.
551
+ if (err && err.code === "auth-openid-federation/chain-cycle") throw err;
529
552
  var errCode = (err && err.code) || "unknown";
530
- // Network / 404 / parse errors at the AUTHORITY-fetch step
531
- // are acceptable "try the next hint" signals. Verify-side
532
- // failures (crypto) are NOT — surface them and abort.
533
- if (/^auth-openid-federation\/(?:bad-jwk|alg-kty-mismatch|bad-signature|signature-failed)$/.test(errCode)) {
534
- throw err;
535
- }
536
553
  ascentErrors.push({ authority: authority, code: errCode, message: (err && err.message) || String(err) });
537
554
  }
538
555
  }
539
556
  if (!ascended) {
540
557
  throw new AuthError("auth-openid-federation/no-ascent",
541
- "entity \"" + current + "\" has authority_hints but none yielded a verifiable subordinate statement: " +
558
+ "entity \"" + current + "\" has authority_hints but none yielded a fetchable subordinate statement: " +
542
559
  JSON.stringify(ascentErrors));
543
560
  }
544
561
  depth += 1;
545
562
  }
546
- throw new AuthError("auth-openid-federation/chain-too-deep",
547
- "buildTrustChain: max depth " + maxDepth + " exceeded; refused");
563
+ if (!reachedAnchor) {
564
+ throw new AuthError("auth-openid-federation/chain-too-deep",
565
+ "buildTrustChain: max depth " + maxDepth + " exceeded; refused");
566
+ }
567
+
568
+ // ---- Phase 2: verify top-down against attested keys ----------------
569
+ // Trust flows from the operator-pinned anchor downward. Each
570
+ // subordinate statement is signed by the superior directly above the
571
+ // entity it describes, and pins that entity's jwks. We start with the
572
+ // anchor's pinned keys and, for each step down, verify the subordinate
573
+ // statement with the keys attested for its SIGNER (never the signer's
574
+ // self-published config), then adopt the statement's attested jwks as
575
+ // the trusted keys for the next step. This closes the fetch-time TOCTOU
576
+ // and makes the anchor key gate every link, not just the anchor's own
577
+ // self-config.
578
+ var anchorEntityId = chain[chain.length - 1].claims.iss;
579
+ var attestedJwks = opts.trustAnchors[anchorEntityId];
580
+ for (var ci = chain.length - 2; ci >= 0; ci--) {
581
+ var node = chain[ci];
582
+ if (!node.subordinate || !node.subordinateJwt) {
583
+ // Every non-anchor node must carry the superior-signed statement
584
+ // collected in Phase 1; its absence is an internal invariant break.
585
+ throw new AuthError("auth-openid-federation/no-subordinate",
586
+ "buildTrustChain: entity \"" + node.claims.iss + "\" has no superior-signed subordinate statement");
587
+ }
588
+ // Verify against the SIGNER's attested keys (flowed down), not the
589
+ // signer's self-published config jwks.
590
+ verifyEntityStatement(node.subordinateJwt, attestedJwks || {});
591
+ // The subordinate statement pins this entity's jwks — adopt the
592
+ // attested keys for the next link down, and reflect them on the node.
593
+ if (node.subordinate.jwks && Array.isArray(node.subordinate.jwks.keys)) {
594
+ node.claims.jwks = node.subordinate.jwks;
595
+ attestedJwks = node.subordinate.jwks;
596
+ } else {
597
+ // A subordinate statement that pins no keys cannot attest the next
598
+ // link — refuse rather than fall back to self-published keys.
599
+ throw new AuthError("auth-openid-federation/no-attested-jwks",
600
+ "subordinate statement for \"" + node.claims.iss + "\" pins no jwks; cannot attest the chain downward");
601
+ }
602
+ }
603
+
604
+ _emitAudit("chain_built", "success", {
605
+ leaf: opts.leafEntityId, depth: chain.length, anchor: anchorEntityId,
606
+ });
607
+ _emitMetric("chain-built");
608
+ return chain;
548
609
  }
549
610
 
550
611
  /**
@@ -684,10 +684,11 @@ function create(opts) {
684
684
  // as Bearer (Profile §3.1 incorporates §3 by reference).
685
685
  var nbHok = _attr(scdHok, "NotBefore");
686
686
  var noaHok = _attr(scdHok, "NotOnOrAfter");
687
+ if (!noaHok) continue; // §3.1 (incorporates §3) — time-bound required
688
+ var noaHokSec = Date.parse(noaHok) / 1000; // ms→s
689
+ if (!isFinite(noaHokSec) || noaHokSec < nowSec - clockSkewSec) continue; // unparseable or expired
687
690
  if (nbHok && isFinite(Date.parse(nbHok) / 1000) && // ms→s
688
691
  Date.parse(nbHok) / 1000 > nowSec + clockSkewSec) continue; // ms→s
689
- if (noaHok && isFinite(Date.parse(noaHok) / 1000) && // ms→s
690
- Date.parse(noaHok) / 1000 < nowSec - clockSkewSec) continue; // ms→s
691
692
  var recipHok = _attr(scdHok, "Recipient");
692
693
  if (recipHok && recipHok !== opts.assertionConsumerServiceUrl) continue;
693
694
  hokOk = true;
@@ -697,12 +698,9 @@ function create(opts) {
697
698
  var scd = _findChild(sc, "SubjectConfirmationData", SAML_NS.assertion);
698
699
  if (!scd) continue;
699
700
  var notOnOrAfter = _attr(scd, "NotOnOrAfter");
700
- if (notOnOrAfter) {
701
- var t = Date.parse(notOnOrAfter) / 1000; // ms→s
702
- if (!isFinite(t) || t < nowSec - clockSkewSec) {
703
- continue; // expired confirmation — try next
704
- }
705
- }
701
+ if (!notOnOrAfter) continue; // §4.1.4.2 — Bearer requires NotOnOrAfter (no unbounded freshness)
702
+ var t = Date.parse(notOnOrAfter) / 1000; // ms→s
703
+ if (!isFinite(t) || t < nowSec - clockSkewSec) continue; // unparseable or expired confirmation — try next
706
704
  var notBefore = _attr(scd, "NotBefore");
707
705
  if (notBefore) {
708
706
  var nb = Date.parse(notBefore) / 1000; // ms→s
@@ -126,12 +126,25 @@ function _hashDisclosure(disclosureStr, hashAlg) {
126
126
  return h.digest().toString("base64url");
127
127
  }
128
128
 
129
+ // JOSE/JWS — and EUDI wallets — require ECDSA signatures as raw r||s
130
+ // ("ieee-p1363"); node:crypto defaults to DER (ASN.1 SEQUENCE). Wrap the EC
131
+ // key so ES256/ES384 sign + verify emit/expect the JOSE encoding. Without it
132
+ // a token this library signs is rejected by every conformant verifier (and
133
+ // the library rejects their raw-r||s KB-JWTs). EdDSA / ML-DSA keys pass
134
+ // through unchanged. Mirrors oauth.js / dpop.js / jwt-external.js.
135
+ function _ecKeyParam(algorithm, key) {
136
+ if (algorithm === "ES256" || algorithm === "ES384") {
137
+ return { key: key, dsaEncoding: "ieee-p1363" };
138
+ }
139
+ return key;
140
+ }
141
+
129
142
  function _signJwt(header, payload, privateKey, algorithm) {
130
143
  var headerStr = _b64uEncode(safeJson.stringify(header));
131
144
  var payloadStr = _b64uEncode(safeJson.stringify(payload));
132
145
  var signingInput = headerStr + "." + payloadStr;
133
146
  var sigAlgo = _resolveSigAlgo(algorithm);
134
- var sig = nodeCrypto.sign(sigAlgo, Buffer.from(signingInput, "ascii"), privateKey);
147
+ var sig = nodeCrypto.sign(sigAlgo, Buffer.from(signingInput, "ascii"), _ecKeyParam(algorithm, privateKey));
135
148
  return signingInput + "." + sig.toString("base64url");
136
149
  }
137
150
 
@@ -144,7 +157,7 @@ function _verifyJwt(token, publicKey, algorithm) {
144
157
  var signingInput = parts[0] + "." + parts[1];
145
158
  var sig = _b64uDecodeBuf(parts[2]);
146
159
  var sigAlgo = _resolveSigAlgo(algorithm);
147
- var ok = nodeCrypto.verify(sigAlgo, Buffer.from(signingInput, "ascii"), publicKey, sig);
160
+ var ok = nodeCrypto.verify(sigAlgo, Buffer.from(signingInput, "ascii"), _ecKeyParam(algorithm, publicKey), sig);
148
161
  if (!ok) {
149
162
  throw new AuthError("auth-sd-jwt-vc/bad-signature",
150
163
  "JWT signature verification failed");
@@ -482,9 +495,13 @@ async function verify(presentation, opts) {
482
495
  "verify: issuerKeyResolver returned no key");
483
496
  }
484
497
  // CVE-2026-22817 — when issuerKeyResolver returns a JWK object,
485
- // cross-check alg/kty BEFORE handing it to node:crypto.verify.
486
- // KeyObject / PEM shapes can't surface kty so the check happens at
487
- // JWK resolution only.
498
+ // cross-check the issuer JWS alg/kty BEFORE handing it to
499
+ // node:crypto.verify. KeyObject / PEM shapes can't surface kty, so this
500
+ // guard only fires when the resolver hands back a JWK (the common path).
501
+ // The holder KB-JWT path applies its OWN _assertAlgKtyMatch against the
502
+ // cnf.jwk below — note that the holder key is issuer-ATTESTED (it comes
503
+ // from the cryptographically-verified issuer payload's cnf claim), not
504
+ // header-resolved, so the two cross-checks defend different trust edges.
488
505
  if (typeof issuerKey === "object" &&
489
506
  !(issuerKey instanceof nodeCrypto.KeyObject) &&
490
507
  !Buffer.isBuffer(issuerKey) &&
@@ -610,6 +627,15 @@ async function verify(presentation, opts) {
610
627
  throw new AuthError("auth-sd-jwt-vc/unsupported-alg",
611
628
  "verify: KB-JWT alg unsupported");
612
629
  }
630
+ // CVE-2026-22817 — cross-check the KB-JWT header alg against the holder
631
+ // key type BEFORE importing the key / verifying. The issuer path does
632
+ // this for issuerKey (above); the holder KB-JWT path must too. The
633
+ // KB-JWT header alg is attacker-controllable (the holder mints the
634
+ // KB-JWT), and holderKey is a cnf.jwk with a kty, so an alg/kty
635
+ // mismatch (e.g. a header claiming EdDSA against an EC cnf key) is
636
+ // refused with the precise alg-mismatch error rather than handed to
637
+ // node:crypto.verify.
638
+ jwtExternal._assertAlgKtyMatch(kbAlg, holderKey);
613
639
  var holderKeyObj = nodeCrypto.createPublicKey({ key: holderKey, format: "jwk" });
614
640
  var kbParsed = _verifyJwt(maybeKbJwt, holderKeyObj, kbAlg);
615
641
  if (opts.audience && kbParsed.payload.aud !== opts.audience) {
@@ -54,6 +54,7 @@ var nodePath = require("node:path");
54
54
  var bCrypto = require("../crypto");
55
55
  var atomicFile = require("../atomic-file");
56
56
  var backupBundle = require("./bundle");
57
+ var frameworkFiles = require("../framework-files");
57
58
  var backupManifest = require("./manifest");
58
59
  var lazyRequire = require("../lazy-require");
59
60
  var validateOpts = require("../validate-opts");
@@ -65,6 +66,7 @@ var compliance = lazyRequire(function () { return require("../compliance"); });
65
66
  // module graph (CLI tools, stand-alone backup runners). The db()
66
67
  // callable resolves on first access.
67
68
  var dbModuleLazy = lazyRequire(function () { return require("../db"); });
69
+ var cryptoField = lazyRequire(function () { return require("../crypto-field"); });
68
70
  var archiveLazy = lazyRequire(function () { return require("../archive"); });
69
71
  var archiveAdaptersLazy = lazyRequire(function () { return require("../archive-adapters"); });
70
72
  var { defineClass } = require("../framework-error");
@@ -416,6 +418,37 @@ function create(opts) {
416
418
  });
417
419
  } catch (_e) { /* drop-silent */ }
418
420
  }
421
+ // Per-row residency blind spot: the deployment-level check above only
422
+ // compares the single DB region to the destination. A per-row-residency
423
+ // table is DECLARED (cryptoField.declarePerRowResidency) to admit rows in
424
+ // several regions; rows tagged to a region other than the backup
425
+ // destination are a per-row cross-border transfer the deployment compare
426
+ // cannot see. Surface the declared cross-border regions (policy-based —
427
+ // no row scan) so the bundle's residency exposure is visible.
428
+ if (backupResidencyTag) {
429
+ try {
430
+ var perRowTables = cryptoField().listPerRowResidency();
431
+ var perRowCrossBorder = [];
432
+ for (var pri = 0; pri < perRowTables.length; pri++) {
433
+ var prt = perRowTables[pri];
434
+ var offending = (prt.allowedTags || []).filter(function (tag) {
435
+ return tag !== "global" && tag !== "unrestricted" && tag !== backupResidencyTag;
436
+ });
437
+ if (offending.length) perRowCrossBorder.push({ table: prt.table, regions: offending });
438
+ }
439
+ if (perRowCrossBorder.length) {
440
+ audit().safeEmit({
441
+ action: "backup.residency.per_row_cross_border",
442
+ outcome: "success",
443
+ metadata: {
444
+ severity: "warning", scope: "per-row", posture: posture,
445
+ destination: backupResidencyTag, tables: perRowCrossBorder,
446
+ recommendation: "a per-row-residency table admits rows in regions other than the backup destination; confirm the cross-border transfer is permitted (allowCrossBorder + documented legalBasis) or restrict the destination region",
447
+ },
448
+ });
449
+ }
450
+ } catch (_e) { /* drop-silent — advisory only */ }
451
+ }
419
452
  }
420
453
 
421
454
  var dataDir = opts.dataDir;
@@ -887,21 +920,23 @@ function recommendedFiles(opts) {
887
920
  var files = [];
888
921
 
889
922
  if (atRest === "encrypted") {
890
- files.push({ relativePath: "db.enc", kind: "raw", required: true });
891
- files.push({ relativePath: "db.key.enc", kind: "raw", required: true });
923
+ files.push({ relativePath: frameworkFiles.fileName("dbEnc"), kind: "raw", required: true });
924
+ files.push({ relativePath: frameworkFiles.fileName("dbKeyEnc"), kind: "raw", required: true });
892
925
  } else {
893
926
  files.push({ relativePath: dbName, kind: "raw", required: true });
894
927
  }
895
928
 
896
929
  if (vaultMode === "wrapped") {
897
- files.push({ relativePath: "vault.key.sealed", kind: "raw", required: true });
930
+ files.push({ relativePath: frameworkFiles.fileName("vaultKey") + ".sealed", kind: "raw", required: true });
898
931
  } else {
899
- files.push({ relativePath: "vault.key", kind: "raw", required: true });
932
+ files.push({ relativePath: frameworkFiles.fileName("vaultKey"), kind: "raw", required: true });
900
933
  }
901
934
 
902
935
  // Audit-signing key (always present; sealed in wrapped mode)
903
936
  files.push({
904
- relativePath: vaultMode === "wrapped" ? "audit-sign.key.sealed" : "audit-sign.key",
937
+ relativePath: vaultMode === "wrapped"
938
+ ? frameworkFiles.fileName("auditSignKey") + ".sealed"
939
+ : frameworkFiles.fileName("auditSignKey"),
905
940
  kind: "raw", required: false,
906
941
  });
907
942
 
@@ -2368,7 +2403,7 @@ bundleAdapterStorage.objectStoreAdapter = function (client, osOpts) {
2368
2403
  // b.objectStore surfaces NOT_FOUND via the framework's
2369
2404
  // err.code === "NOT_FOUND" convention — translate to the
2370
2405
  // backup adapter contract's no-key error.
2371
- if (e && (e.code === "NOT_FOUND" || /NOT_FOUND|not found/i.test(e.message || ""))) {
2406
+ if (e && (e.code === "NOT_FOUND" || e.statusCode === 404 || /NOT_FOUND|not found/i.test(e.message || ""))) {
2372
2407
  throw new BackupError("backup/no-key",
2373
2408
  "objectStoreAdapter: key not found: " + JSON.stringify(key));
2374
2409
  }
@@ -2425,7 +2460,7 @@ bundleAdapterStorage.objectStoreAdapter = function (client, osOpts) {
2425
2460
  } catch (e) {
2426
2461
  // drop-silent on NOT_FOUND — adapter contract is idempotent
2427
2462
  // delete (fsAdapter same shape).
2428
- if (e && (e.code === "NOT_FOUND" || /NOT_FOUND|not found/i.test(e.message || ""))) {
2463
+ if (e && (e.code === "NOT_FOUND" || e.statusCode === 404 || /NOT_FOUND|not found/i.test(e.message || ""))) {
2429
2464
  return;
2430
2465
  }
2431
2466
  throw e;
@@ -2436,7 +2471,7 @@ bundleAdapterStorage.objectStoreAdapter = function (client, osOpts) {
2436
2471
  await client.head(_scopedKey(key));
2437
2472
  return true;
2438
2473
  } catch (e) {
2439
- if (e && (e.code === "NOT_FOUND" || /NOT_FOUND|not found/i.test(e.message || ""))) {
2474
+ if (e && (e.code === "NOT_FOUND" || e.statusCode === 404 || /NOT_FOUND|not found/i.test(e.message || ""))) {
2440
2475
  return false;
2441
2476
  }
2442
2477
  throw e;
@@ -2453,7 +2488,7 @@ bundleAdapterStorage.objectStoreAdapter = function (client, osOpts) {
2453
2488
  var buf = Buffer.isBuffer(body) ? body : Buffer.from(body);
2454
2489
  return buf.slice(0, length);
2455
2490
  } catch (e) {
2456
- if (e && (e.code === "NOT_FOUND" || /NOT_FOUND|not found/i.test(e.message || ""))) {
2491
+ if (e && (e.code === "NOT_FOUND" || e.statusCode === 404 || /NOT_FOUND|not found/i.test(e.message || ""))) {
2457
2492
  throw new BackupError("backup/no-key",
2458
2493
  "objectStoreAdapter.readPartial: key not found: " + JSON.stringify(key));
2459
2494
  }
@@ -2466,7 +2501,7 @@ bundleAdapterStorage.objectStoreAdapter = function (client, osOpts) {
2466
2501
  if (!meta || typeof meta.size !== "number") return null;
2467
2502
  return { size: meta.size, mtimeMs: meta.lastModified || null };
2468
2503
  } catch (e) {
2469
- if (e && (e.code === "NOT_FOUND" || /NOT_FOUND|not found/i.test(e.message || ""))) {
2504
+ if (e && (e.code === "NOT_FOUND" || e.statusCode === 404 || /NOT_FOUND|not found/i.test(e.message || ""))) {
2470
2505
  return null;
2471
2506
  }
2472
2507
  throw e;