@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
@@ -214,6 +214,11 @@ function create(config) {
214
214
  var timeoutMs = config.timeoutMs;
215
215
  var allowedProtocols = config.allowedProtocols || safeUrl.ALLOW_HTTP_TLS;
216
216
  var allowInternal = config.allowInternal != null ? config.allowInternal : null;
217
+ // Account placement — see azure-blob.js create(). Default host-based; opt
218
+ // into path-style (Azurite / Azure Stack / private) with config.pathStyle:
219
+ // true. Default false keeps the host-based wire shape unchanged.
220
+ var pathStyle = config.pathStyle === true;
221
+ var pathPrefix = pathStyle ? ("/" + config.accountName) : "";
217
222
 
218
223
  function _sign(method, url, headers) {
219
224
  return azureBlob.signRequest({
@@ -260,7 +265,7 @@ function create(config) {
260
265
  async function createContainer(name, opts) {
261
266
  _validateContainerName(name);
262
267
  opts = opts || {};
263
- var url = _internalUrl(endpoint + "/" + name + "?restype=container", allowedProtocols);
268
+ var url = _internalUrl(endpoint + pathPrefix + "/" + name + "?restype=container", allowedProtocols);
264
269
  var headers = { "Content-Length": "0" };
265
270
  if (opts.publicAccess) {
266
271
  if (opts.publicAccess !== "blob" && opts.publicAccess !== "container") {
@@ -282,7 +287,7 @@ function create(config) {
282
287
 
283
288
  async function deleteContainer(name) {
284
289
  _validateContainerName(name);
285
- var url = _internalUrl(endpoint + "/" + name + "?restype=container", allowedProtocols);
290
+ var url = _internalUrl(endpoint + pathPrefix + "/" + name + "?restype=container", allowedProtocols);
286
291
  var signed = _sign("DELETE", url, {});
287
292
  var res = await _request("DELETE", url, signed, null, [HTTP_ACCEPTED, HTTP_NOT_FOUND]);
288
293
  return res.statusCode === HTTP_ACCEPTED;
@@ -290,7 +295,7 @@ function create(config) {
290
295
 
291
296
  async function listContainers(opts) {
292
297
  opts = opts || {};
293
- var url = _internalUrl(endpoint + "/?comp=list", allowedProtocols);
298
+ var url = _internalUrl(endpoint + pathPrefix + "/?comp=list", allowedProtocols);
294
299
  if (opts.prefix) url.searchParams.set("prefix", opts.prefix);
295
300
  if (opts.maxResults != null) url.searchParams.set("maxresults", String(opts.maxResults));
296
301
  var signed = _sign("GET", url, {});
@@ -319,7 +324,7 @@ function create(config) {
319
324
  rules.forEach(_validateCorsRule);
320
325
  var xml = _buildCorsXml(rules);
321
326
  var bodyBuf = Buffer.from(xml, "utf8");
322
- var url = _internalUrl(endpoint + "/?restype=service&comp=properties", allowedProtocols);
327
+ var url = _internalUrl(endpoint + pathPrefix + "/?restype=service&comp=properties", allowedProtocols);
323
328
  var headers = {
324
329
  "Content-Type": "application/xml",
325
330
  "Content-Length": String(bodyBuf.length),
@@ -15,6 +15,11 @@
15
15
  * accountKey: '<base64 storage key>' // required (REST shared key)
16
16
  * container: 'my-container' // required
17
17
  * endpoint: 'https://...' // optional override
18
+ * pathStyle: true // optional; account as the first
19
+ * // URL path segment (Azurite / Azure
20
+ * // Stack / private endpoints).
21
+ * // Default false = host-based
22
+ * // (<account>.blob.core.windows.net).
18
23
  * apiVersion: '2024-08-04' // x-ms-version header
19
24
  * timeoutMs: C.TIME.seconds(30)
20
25
  * }
@@ -35,6 +40,7 @@ var { URL } = require("node:url");
35
40
  var { Readable } = require("node:stream");
36
41
  var safeXml = require("../parsers/safe-xml");
37
42
  var sharedRequest = require("./http-request");
43
+ var sigv4 = require("./sigv4");
38
44
  var C = require("../constants");
39
45
  var requestHelpers = require("../request-helpers");
40
46
  var { ObjectStoreError } = require("../framework-error");
@@ -65,6 +71,26 @@ function _arrayify(value) {
65
71
  return Array.isArray(value) ? value : [value];
66
72
  }
67
73
 
74
+ // Percent-encode a hierarchical blob name for use in a URL path. Azure
75
+ // blob names are `/`-delimited virtual directories, so each segment is
76
+ // RFC 3986 percent-encoded (via the family-shared encoder used by the
77
+ // S3 / GCS backends) while the `/` separators are preserved. Without
78
+ // this, a key containing `?`, `#`, a space, or other reserved chars is
79
+ // interpolated raw into the request URL — `?`/`#` start the query /
80
+ // fragment (so the blob path is truncated, hitting the wrong object or
81
+ // the container root), and spaces / control bytes corrupt the request
82
+ // line (CWE-20 improper input → request-smuggling-adjacent). A null
83
+ // byte is refused outright (it can't appear in a valid blob name and
84
+ // indicates a malformed / hostile key), matching the S3 / GCS guards.
85
+ function _encodeBlobKey(key) {
86
+ if (key.indexOf("\0") !== -1) {
87
+ throw _err("INVALID_KEY", "null byte in blob key", true);
88
+ }
89
+ return key.split("/").map(function (s) {
90
+ return sigv4.awsUriEncode(s, true);
91
+ }).join("/");
92
+ }
93
+
68
94
  var DEFAULT_API_VERSION = "2024-08-04";
69
95
 
70
96
  // Service SAS expiry bounds. Azure doesn't enforce a hard max, but
@@ -120,6 +146,17 @@ function buildStringToSign(opts) {
120
146
  var canonicalResource = (function () {
121
147
  // /<account>/<rest of path>
122
148
  // Plus sorted query params, each "name:value\n"
149
+ // Canonicalized resource per the Shared Key spec: "/" + account + the
150
+ // request's absolute path + sorted query. Host-based endpoints
151
+ // (production <account>.blob.core.windows.net) have url.pathname
152
+ // "/<container>/<blob>", giving "/<account>/<container>/<blob>".
153
+ // Path-style endpoints (Azurite / Azure Stack / private) already carry
154
+ // "/<account>" as the first path segment, so the account appears twice
155
+ // ("/<account>/<account>/<container>/<blob>") — which is exactly what a
156
+ // path-style server expects: it prepends the account to the full request
157
+ // path it received. Verified against Azurite — the doubled form is the
158
+ // one that authenticates; the URL itself must carry the account in its
159
+ // path (see pathPrefix in create()).
123
160
  var resourcePath = "/" + opts.accountName + url.pathname;
124
161
  var paramPairs = [];
125
162
  url.searchParams.forEach(function (v, k) {
@@ -204,11 +241,24 @@ function create(config) {
204
241
  var allowedProtocols = config.allowedProtocols || safeUrl.ALLOW_HTTP_TLS;
205
242
  var allowInternal = config.allowInternal != null ? config.allowInternal : null;
206
243
  safeUrl.parse(endpoint, { allowedProtocols: allowedProtocols, errorClass: ObjectStoreError });
244
+ // Account placement. Default host-based — production Azure is
245
+ // https://<account>.blob.core.windows.net/<container>/<blob> (account in the
246
+ // host). Path-style endpoints (Azurite / Azure Stack / private) carry the
247
+ // account as the first PATH segment instead —
248
+ // https://<host>/<account>/<container>/<blob> — opt in with
249
+ // config.pathStyle:true. Default false keeps the host-based wire shape
250
+ // unchanged for existing deployments (no silent breaking change). The signed
251
+ // canonicalized resource is always "/" + account + url.pathname, so for a
252
+ // path-style URL the account appears twice — which is exactly what a
253
+ // path-style server expects (see buildStringToSign).
254
+ var pathStyle = config.pathStyle === true;
255
+ var pathPrefix = pathStyle ? ("/" + config.accountName) : "";
207
256
  var reqOpts = { timeoutMs: timeoutMs, allowedProtocols: allowedProtocols };
208
257
  if (allowInternal !== null) reqOpts.allowInternal = allowInternal;
209
258
 
210
259
  function _blobUrl(key, params) {
211
- var u = _internalUrl(endpoint + "/" + config.container + "/" + key, allowedProtocols);
260
+ var u = _internalUrl(endpoint + pathPrefix + "/" + config.container + "/" + _encodeBlobKey(key),
261
+ allowedProtocols);
212
262
  if (params) {
213
263
  Object.keys(params).forEach(function (k) { u.searchParams.set(k, params[k]); });
214
264
  }
@@ -216,7 +266,7 @@ function create(config) {
216
266
  }
217
267
 
218
268
  function _containerUrl(params) {
219
- var u = _internalUrl(endpoint + "/" + config.container, allowedProtocols);
269
+ var u = _internalUrl(endpoint + pathPrefix + "/" + config.container, allowedProtocols);
220
270
  if (params) {
221
271
  Object.keys(params).forEach(function (k) { u.searchParams.set(k, params[k]); });
222
272
  }
@@ -425,8 +475,12 @@ function create(config) {
425
475
  throw _err("INVALID_KEY", "null byte in key", true);
426
476
  }
427
477
 
478
+ // _buildSasToken signs the canonicalized resource with the RAW
479
+ // (decoded) blob name per the Azure SAS spec; the URL PATH carries the
480
+ // percent-encoded key so a key with reserved chars (`?` / `#` / space)
481
+ // doesn't truncate the path or corrupt the request line.
428
482
  var token = _buildSasToken(permissions, opts);
429
- var url = _internalUrl(endpoint + "/" + config.container + "/" + opts.key + "?" + token.sas, allowedProtocols);
483
+ var url = _internalUrl(endpoint + pathPrefix + "/" + config.container + "/" + _encodeBlobKey(opts.key) + "?" + token.sas, allowedProtocols);
430
484
 
431
485
  var clientHeaders = {};
432
486
  if (opts.contentType) clientHeaders["Content-Type"] = opts.contentType;
@@ -364,7 +364,10 @@ function create(config) {
364
364
  // Build the canonical request — identical shape to SigV4. The
365
365
  // sigv4 export gives us the formatter so this stays in lockstep
366
366
  // with the AWS implementation.
367
- var canon = sigv4.canonicalRequest(method, url, headers, "UNSIGNED-PAYLOAD");
367
+ // GCS's V4 signature, like S3, URI-encodes the canonical path ONCE; the key
368
+ // is already single-encoded into url.pathname above, so pass doubleEncodePath
369
+ // = false (a second encode would 403 any key with a space/+/&/unicode).
370
+ var canon = sigv4.canonicalRequest(method, url, headers, "UNSIGNED-PAYLOAD", false);
368
371
  var stringToSign = [
369
372
  GCS_V4_ALGORITHM,
370
373
  amzDate,
@@ -514,8 +514,11 @@ function create(config) {
514
514
  function _objectUrl(name, key, query) {
515
515
  // Each key segment is encoded individually so that legitimate "/"
516
516
  // separators in the key are preserved (S3 treats keys with slashes
517
- // as flat names, not directories).
518
- var encKey = key.split("/").map(encodeURIComponent).join("/");
517
+ // as flat names, not directories). Use sigv4.awsUriEncode (not
518
+ // encodeURIComponent, which leaves !*'() unescaped) so the wire path
519
+ // matches the bytes S3 canonicalizes the signature over — same encoder
520
+ // _keyToUrl uses for the put/get path.
521
+ var encKey = key.split("/").map(function (s) { return sigv4.awsUriEncode(s, true); }).join("/");
519
522
  var uo = _internalUrl(endpoint, allowedProtocols);
520
523
  if (pathStyle) {
521
524
  uo.pathname = "/" + name + "/" + encKey;
@@ -86,9 +86,16 @@ function hmacSha256(key, data) {
86
86
  // AWS-style URI encoding: same as RFC 3986 except path '/' may be preserved.
87
87
  function awsUriEncode(str, encodeSlash) {
88
88
  var out = "";
89
- for (var i = 0; i < str.length; i++) {
90
- var c = str.charCodeAt(i);
91
- var ch = str.charAt(i);
89
+ // Iterate by Unicode code point, not UTF-16 code unit. Array.from() keeps a
90
+ // non-BMP character's surrogate pair together (one element), so a key like
91
+ // "photo-<U+1F600>.jpg" encodes as a single UTF-8 sequence. Iterating by
92
+ // index would hand encodeURIComponent a lone surrogate, which throws
93
+ // "URIError: URI malformed". Output is byte-for-byte identical for the
94
+ // BMP/ASCII keys that are the overwhelming common case.
95
+ var cps = Array.from(str);
96
+ for (var i = 0; i < cps.length; i++) {
97
+ var ch = cps[i];
98
+ var c = ch.codePointAt(0);
92
99
  if ((c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A) ||
93
100
  (c >= 0x30 && c <= 0x39) ||
94
101
  ch === "-" || ch === "_" || ch === "." || ch === "~") {
@@ -137,13 +144,24 @@ function canonicalHeaders(headers) {
137
144
  return { canonical: canon, signed: signed.join(";") };
138
145
  }
139
146
 
140
- function canonicalRequest(method, urlObj, headers, payloadHash) {
147
+ // AWS SigV4 canonical URI. Per the SigV4 spec, S3 (and S3-compatible stores +
148
+ // GCS's V4) URI-encode the path EXACTLY ONCE; every other AWS service (sqs,
149
+ // logs, sns, ...) encodes it TWICE. Callers build urlObj through the WHATWG URL
150
+ // parser, so urlObj.pathname is ALREADY the single-encoded wire form (a key
151
+ // "a b.txt" is "/a%20b.txt") and the request sends that pathname verbatim. So
152
+ // for S3/GCS the canonical path MUST equal the pathname as-is: a second
153
+ // awsUriEncode would sign "/a%2520b.txt", a path the wire never carries, giving
154
+ // SignatureDoesNotMatch (403) for any key with a space/+/&/unicode. For the
155
+ // double-encode services the second pass is the spec requirement. signRequest
156
+ // derives doubleEncodePath from the service; GCS's V4 signer passes false.
157
+ function canonicalRequest(method, urlObj, headers, payloadHash, doubleEncodePath) {
141
158
  var canonHeaders = canonicalHeaders(headers);
142
159
  var path = urlObj.pathname;
143
160
  if (!path) path = "/";
161
+ var canonicalPath = doubleEncodePath ? awsUriEncode(path, false) : path;
144
162
  return [
145
163
  method.toUpperCase(),
146
- awsUriEncode(path, false),
164
+ canonicalPath,
147
165
  canonicalQueryString(urlObj.searchParams),
148
166
  canonHeaders.canonical,
149
167
  canonHeaders.signed,
@@ -204,7 +222,11 @@ function signRequest(opts) {
204
222
  headers["x-amz-security-token"] = opts.sessionToken;
205
223
  }
206
224
 
207
- var canon = canonicalRequest(opts.method, url, headers, opts.payloadHash);
225
+ // S3 single-encodes the canonical path; every other AWS service double-encodes
226
+ // it (see canonicalRequest). The path itself is "/" for the non-S3 callers
227
+ // (cloudwatch/sqs put params in the query or body), so this only changes the
228
+ // wire result for S3, where it fixes the long-standing double-encode 403.
229
+ var canon = canonicalRequest(opts.method, url, headers, opts.payloadHash, service !== "s3");
208
230
  var credentialScope = dateStamp + "/" + opts.region + "/" + service + "/aws4_request";
209
231
  var sts = stringToSign(amzDate, credentialScope, canon);
210
232
  var signingKey = deriveSigningKey(opts.secretAccessKey, dateStamp, opts.region, service);
@@ -661,6 +683,16 @@ function create(config) {
661
683
  etag: res.headers.etag,
662
684
  lastModified: res.headers["last-modified"] ? Date.parse(res.headers["last-modified"]) : null,
663
685
  };
686
+ }, function (e) {
687
+ // A missing key surfaces as the framework NOT_FOUND code — the same
688
+ // contract local.js head() exposes and that deleteKey already maps 404
689
+ // to — so existence probes via head() (e.g. the backup objectStore
690
+ // adapter's hasKey / statKey) get the uniform missing-key signal instead
691
+ // of a raw HTTP 404 they don't recognize.
692
+ if (e && e.statusCode === 404) {
693
+ throw _err("NOT_FOUND", "key not found: " + key, true);
694
+ }
695
+ throw e;
664
696
  });
665
697
  }
666
698
 
@@ -98,6 +98,11 @@ var KIND_TO_OTLP = Object.freeze({
98
98
  function _attrToOtlp(attrs) {
99
99
  // OTLP attribute shape: [{ key, value: { stringValue | intValue |
100
100
  // doubleValue | boolValue | arrayValue: { values: [...] } } }, ...]
101
+ // Telemetry is a first-class EGRESS sink — scrub every value through the
102
+ // active redactor BEFORE serialization so a secret/PII attribute never
103
+ // reaches the collector (CWE-532). Redaction is baked into the encoder, not
104
+ // the call site, so no span/event/resource path can forget it.
105
+ attrs = observability().redactAttrs(attrs);
101
106
  var out = [];
102
107
  if (!attrs || typeof attrs !== "object") return out;
103
108
  var keys = Object.keys(attrs);
@@ -316,7 +321,10 @@ function _keyValueToProto(kvObj) {
316
321
  function _attrsToProto(attrs) {
317
322
  // attrs is the raw `{ key: value }` operator attribute object; OTLP
318
323
  // KeyValue gets emitted per entry with field 9 (attributes) on Span,
319
- // field 1 (attributes) on Resource, etc.
324
+ // field 1 (attributes) on Resource, etc. Scrub every value through the
325
+ // active redactor BEFORE building the wire intermediate — the protobuf path
326
+ // is the same EGRESS sink as the JSON path and must not leak (CWE-532).
327
+ attrs = observability().redactAttrs(attrs);
320
328
  if (!attrs || typeof attrs !== "object") return [];
321
329
  var keys = Object.keys(attrs);
322
330
  var out = new Array(keys.length);
@@ -55,6 +55,14 @@ var safeBuffer = lazyRequire(function () { return require("./safe-buffer"); });
55
55
  var tracing = lazyRequire(function () { return require("./tracing"); });
56
56
  var metrics = lazyRequire(function () { return require("./metrics"); });
57
57
 
58
+ // redact is the framework's central PII/secret scrubber. Lazy-loaded so
59
+ // the require graph stays acyclic at boot (redact lazy-pulls audit, which
60
+ // pulls observability back). Composed by the default telemetry redactor
61
+ // below so span/metric attribute VALUES are scrubbed before the OTLP
62
+ // exporter serializes them — CWE-532 (insertion of sensitive information
63
+ // into a telemetry/log egress sink).
64
+ var redact = lazyRequire(function () { return require("./redact"); });
65
+
58
66
  // Operator-installed tap handler — wired via setTap(). When non-null,
59
67
  // every observability event/tap dispatch routes here in addition to
60
68
  // the framework's metrics module. Used by b.otelExport.create() so an
@@ -62,6 +70,26 @@ var metrics = lazyRequire(function () { return require("./metrics"); });
62
70
  // emits internally.
63
71
  var _externalTap = null;
64
72
 
73
+ // Telemetry-attribute redactor seam. Span / metric attribute VALUES are
74
+ // a first-class egress surface: a span attribute holding a user email,
75
+ // bearer token, or vault-sealed ciphertext is shipped verbatim to the
76
+ // OTLP collector unless it is scrubbed at the assembly boundary, the same
77
+ // way log-stream redacts every record before any sink sees it. Defaults
78
+ // ON — the default redactor composes b.redact.redact, passing the
79
+ // attribute key as the parent-key context so both field-name rules
80
+ // (authorization / token / session / password) and value-shape detectors
81
+ // (JWT / PEM / credit-card / SSN / connection-string) fire. CWE-532.
82
+ //
83
+ // The redactor is (value, key) → redactedValue. The exporter calls it for
84
+ // every attribute value; a thrown redactor drops the attribute rather
85
+ // than leaking it (the exporter enforces fail-toward-dropping), so a
86
+ // misbehaving custom redactor can never widen the egress surface.
87
+ function _defaultTelemetryRedactor(value, key) {
88
+ return redact().redact(value, { parentKey: typeof key === "string" ? key : null });
89
+ }
90
+
91
+ var _telemetryRedactor = _defaultTelemetryRedactor;
92
+
65
93
  function _safeMetricsTap(name, value, labels) {
66
94
  try { metrics().tap(name, value, labels); }
67
95
  catch (_e) { /* boot-order tolerance — metrics may not be loaded */ }
@@ -106,6 +134,99 @@ function setTap(handler) {
106
134
  _externalTap = handler;
107
135
  }
108
136
 
137
+ /**
138
+ * @primitive b.observability.setRedactor
139
+ * @signature b.observability.setRedactor(redactor)
140
+ * @since 0.14.27
141
+ * @related b.observability.getRedactor, b.redact.redact
142
+ *
143
+ * Override the redactor applied to every span / metric attribute VALUE
144
+ * before the OTLP exporter serializes it onto the wire. Telemetry is a
145
+ * first-class egress sink: an attribute holding a user email, bearer
146
+ * token, or secret would otherwise reach the collector in plaintext
147
+ * (CWE-532). Redaction is ON by default — the default redactor composes
148
+ * `b.redact.redact` and fires both field-name and value-shape rules; this
149
+ * setter only lets an operator swap in a stricter or domain-specific
150
+ * scrubber.
151
+ *
152
+ * The redactor is `redactor(value, key)` and returns the value to export.
153
+ * It runs on the export hot path, so a throw is caught and the attribute
154
+ * is dropped (never exported raw) — a redactor that throws can only
155
+ * shrink the egress surface, never widen it. Pass `null` to restore the
156
+ * default `b.redact.redact`-backed redactor.
157
+ *
158
+ * @example
159
+ * b.observability.setRedactor(function (value, key) {
160
+ * if (key === "enduser.id") return "[REDACTED]";
161
+ * return b.redact.redact(value, { parentKey: key });
162
+ * });
163
+ * b.observability.setRedactor(null); // restore the default
164
+ */
165
+ function setRedactor(redactor) {
166
+ if (redactor !== null && typeof redactor !== "function") {
167
+ throw new TypeError("observability.setRedactor: redactor must be a function or null, got " +
168
+ typeof redactor);
169
+ }
170
+ _telemetryRedactor = redactor === null ? _defaultTelemetryRedactor : redactor;
171
+ }
172
+
173
+ /**
174
+ * @primitive b.observability.getRedactor
175
+ * @signature b.observability.getRedactor()
176
+ * @since 0.14.27
177
+ * @related b.observability.setRedactor, b.redact.redact
178
+ *
179
+ * Return the redactor currently applied to span / metric attribute
180
+ * values on the OTLP egress path. The OTLP exporter calls this to scrub
181
+ * every attribute value before serialization; operators rarely need it
182
+ * directly. When no override has been installed it returns the default
183
+ * `b.redact.redact`-backed redactor.
184
+ *
185
+ * @example
186
+ * var redactor = b.observability.getRedactor();
187
+ * redactor("Bearer eyJabc.eyJdef.sig", "authorization");
188
+ * // → "[REDACTED]" (field-name rule on the "authorization" key)
189
+ */
190
+ function getRedactor() {
191
+ return _telemetryRedactor;
192
+ }
193
+
194
+ /**
195
+ * @primitive b.observability.redactAttrs
196
+ * @signature b.observability.redactAttrs(attrs)
197
+ * @since 0.15.4
198
+ * @related b.observability.getRedactor, b.observability.setRedactor
199
+ *
200
+ * Run every value of a telemetry attribute map through the active redactor and
201
+ * return a NEW `{ key: redactedValue }` object. The OTLP exporters call this on
202
+ * span, span-event, metric, and resource attributes before serialization so no
203
+ * attribute value crosses the egress boundary unscrubbed (CWE-532: insertion of
204
+ * sensitive information into an externally-shipped sink). A key whose redactor
205
+ * throws is DROPPED — failing toward dropping, never exporting the raw value;
206
+ * `null` / `undefined` values pass through for the type-encoder to handle.
207
+ *
208
+ * @example
209
+ * b.observability.redactAttrs({ "http.method": "GET", authorization: "Bearer x" });
210
+ * // → { "http.method": "GET", authorization: "[REDACTED]" }
211
+ */
212
+ function redactAttrs(attrs) {
213
+ var out = {};
214
+ if (!attrs || typeof attrs !== "object") return out;
215
+ var redactor = getRedactor();
216
+ var keys = Object.keys(attrs);
217
+ for (var i = 0; i < keys.length; i++) {
218
+ var k = keys[i];
219
+ try {
220
+ out[k] = redactor(attrs[k], k);
221
+ } catch (_e) {
222
+ // redactor threw on the export hot path — drop the attribute rather than
223
+ // fall through to the raw value. A throwing redactor must never widen the
224
+ // egress surface, and must never crash the request that produced the span.
225
+ }
226
+ }
227
+ return out;
228
+ }
229
+
109
230
  /**
110
231
  * @primitive b.observability.tap
111
232
  * @signature b.observability.tap(name, attrs, fn)
@@ -750,6 +871,9 @@ module.exports = {
750
871
  safeEvent: safeEvent,
751
872
  timed: timed,
752
873
  setTap: setTap,
874
+ setRedactor: setRedactor,
875
+ getRedactor: getRedactor,
876
+ redactAttrs: redactAttrs,
753
877
  SEMCONV: SEMCONV,
754
878
  traceContext: traceContext,
755
879
  baggage: baggage,
@@ -42,6 +42,7 @@
42
42
  var C = require("./constants");
43
43
  var canonicalJson = require("./canonical-json");
44
44
  var httpClient = require("./http-client");
45
+ var observability = require("./observability");
45
46
  var safeAsync = require("./safe-async");
46
47
  var validateOpts = require("./validate-opts");
47
48
  var { defineClass } = require("./framework-error");
@@ -67,11 +68,19 @@ var TEMPORALITY_DELTA = 1;
67
68
  // ---- attribute encoding ----
68
69
  // OTLP attributes are KeyValue with typed `value` fields:
69
70
  // { key, value: { stringValue | intValue | doubleValue | boolValue } }
71
+ // Telemetry is a first-class EGRESS sink — an attribute value holding a user
72
+ // email, bearer token, or vault-sealed ciphertext would otherwise be serialized
73
+ // verbatim onto the OTLP wire (CWE-532). observability.redactAttrs scrubs every
74
+ // value through the active redactor (operator overrides via setRedactor take
75
+ // effect without re-creating the exporter) and drops any key whose redactor
76
+ // throws — failing toward dropping, never leaking, on the export hot path.
70
77
  function _attrsToOtlp(attrs) {
71
- if (!attrs || typeof attrs !== "object") return [];
78
+ attrs = observability.redactAttrs(attrs);
72
79
  var out = [];
73
- for (var k in attrs) {
74
- if (!Object.prototype.hasOwnProperty.call(attrs, k)) continue;
80
+ if (!attrs || typeof attrs !== "object") return out;
81
+ var keys = Object.keys(attrs);
82
+ for (var i = 0; i < keys.length; i++) {
83
+ var k = keys[i];
75
84
  var v = attrs[k];
76
85
  var kv;
77
86
  if (typeof v === "string") kv = { stringValue: v };