@blamejs/blamejs-shop 0.4.31 → 0.4.33

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 (343) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -1
  3. package/lib/asset-manifest.json +1 -1
  4. package/lib/vendor/MANIFEST.json +400 -282
  5. package/lib/vendor/blamejs/.github/workflows/ci.yml +34 -3
  6. package/lib/vendor/blamejs/.github/workflows/npm-publish.yml +21 -4
  7. package/lib/vendor/blamejs/.gitignore +6 -0
  8. package/lib/vendor/blamejs/CHANGELOG.md +28 -0
  9. package/lib/vendor/blamejs/MIGRATING.md +55 -0
  10. package/lib/vendor/blamejs/README.md +8 -6
  11. package/lib/vendor/blamejs/SECURITY.md +19 -3
  12. package/lib/vendor/blamejs/api-snapshot.json +2190 -664
  13. package/lib/vendor/blamejs/docker/caddy/localstack.Caddyfile +19 -0
  14. package/lib/vendor/blamejs/docker/init/generate-certs.sh +1 -1
  15. package/lib/vendor/blamejs/docker/otel/config.yaml +42 -0
  16. package/lib/vendor/blamejs/docker/otel/export/.gitkeep +0 -0
  17. package/lib/vendor/blamejs/docker/postgres/initdb/10-replication.sh +15 -0
  18. package/lib/vendor/blamejs/docker/postgres/replica-entrypoint.sh +38 -0
  19. package/lib/vendor/blamejs/docker/toxiproxy/toxiproxy.json +14 -0
  20. package/lib/vendor/blamejs/docker-compose.test.yml +209 -0
  21. package/lib/vendor/blamejs/examples/wiki/lib/page-generator.js +132 -0
  22. package/lib/vendor/blamejs/examples/wiki/lib/source-comment-block-validator.js +221 -61
  23. package/lib/vendor/blamejs/examples/wiki/lib/source-doc-parser.js +144 -9
  24. package/lib/vendor/blamejs/examples/wiki/test/e2e.js +99 -0
  25. package/lib/vendor/blamejs/fuzz/guard-sql.fuzz.js +36 -0
  26. package/lib/vendor/blamejs/index.js +4 -0
  27. package/lib/vendor/blamejs/lib/agent-envelope-mac.js +104 -0
  28. package/lib/vendor/blamejs/lib/agent-event-bus.js +105 -4
  29. package/lib/vendor/blamejs/lib/agent-posture-chain.js +8 -42
  30. package/lib/vendor/blamejs/lib/ai-content-detect.js +9 -10
  31. package/lib/vendor/blamejs/lib/api-key.js +158 -77
  32. package/lib/vendor/blamejs/lib/atomic-file.js +62 -4
  33. package/lib/vendor/blamejs/lib/audit-chain.js +47 -11
  34. package/lib/vendor/blamejs/lib/audit-sign.js +77 -2
  35. package/lib/vendor/blamejs/lib/audit-tools.js +79 -51
  36. package/lib/vendor/blamejs/lib/audit.js +259 -123
  37. package/lib/vendor/blamejs/lib/auth/elevation-grant.js +6 -2
  38. package/lib/vendor/blamejs/lib/auth/oauth.js +66 -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 +36 -7
  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 +210 -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/credential-hash.js +9 -0
  55. package/lib/vendor/blamejs/lib/crypto-field.js +916 -156
  56. package/lib/vendor/blamejs/lib/db-declare-row-policy.js +35 -22
  57. package/lib/vendor/blamejs/lib/db-file-lifecycle.js +3 -2
  58. package/lib/vendor/blamejs/lib/db-query.js +882 -260
  59. package/lib/vendor/blamejs/lib/db-schema.js +228 -44
  60. package/lib/vendor/blamejs/lib/db.js +249 -99
  61. package/lib/vendor/blamejs/lib/dsr.js +385 -55
  62. package/lib/vendor/blamejs/lib/error-page.js +14 -1
  63. package/lib/vendor/blamejs/lib/external-db-migrate.js +239 -137
  64. package/lib/vendor/blamejs/lib/external-db.js +549 -34
  65. package/lib/vendor/blamejs/lib/file-upload.js +52 -7
  66. package/lib/vendor/blamejs/lib/framework-error.js +20 -1
  67. package/lib/vendor/blamejs/lib/framework-files.js +73 -0
  68. package/lib/vendor/blamejs/lib/framework-schema.js +695 -394
  69. package/lib/vendor/blamejs/lib/gate-contract.js +659 -1
  70. package/lib/vendor/blamejs/lib/guard-agent-registry.js +26 -44
  71. package/lib/vendor/blamejs/lib/guard-all.js +1 -0
  72. package/lib/vendor/blamejs/lib/guard-auth.js +42 -112
  73. package/lib/vendor/blamejs/lib/guard-cidr.js +33 -154
  74. package/lib/vendor/blamejs/lib/guard-csv.js +46 -113
  75. package/lib/vendor/blamejs/lib/guard-domain.js +34 -157
  76. package/lib/vendor/blamejs/lib/guard-dsn.js +27 -43
  77. package/lib/vendor/blamejs/lib/guard-email.js +47 -69
  78. package/lib/vendor/blamejs/lib/guard-envelope.js +19 -32
  79. package/lib/vendor/blamejs/lib/guard-event-bus-payload.js +24 -42
  80. package/lib/vendor/blamejs/lib/guard-event-bus-topic.js +25 -43
  81. package/lib/vendor/blamejs/lib/guard-filename.js +42 -106
  82. package/lib/vendor/blamejs/lib/guard-graphql.js +42 -123
  83. package/lib/vendor/blamejs/lib/guard-html.js +53 -108
  84. package/lib/vendor/blamejs/lib/guard-idempotency-key.js +24 -42
  85. package/lib/vendor/blamejs/lib/guard-image.js +46 -103
  86. package/lib/vendor/blamejs/lib/guard-imap-command.js +18 -32
  87. package/lib/vendor/blamejs/lib/guard-jmap.js +16 -30
  88. package/lib/vendor/blamejs/lib/guard-json.js +38 -108
  89. package/lib/vendor/blamejs/lib/guard-jsonpath.js +38 -171
  90. package/lib/vendor/blamejs/lib/guard-jwt.js +49 -179
  91. package/lib/vendor/blamejs/lib/guard-list-id.js +25 -41
  92. package/lib/vendor/blamejs/lib/guard-list-unsubscribe.js +27 -43
  93. package/lib/vendor/blamejs/lib/guard-mail-compose.js +24 -42
  94. package/lib/vendor/blamejs/lib/guard-mail-move.js +26 -44
  95. package/lib/vendor/blamejs/lib/guard-mail-query.js +28 -46
  96. package/lib/vendor/blamejs/lib/guard-mail-reply.js +24 -42
  97. package/lib/vendor/blamejs/lib/guard-mail-sieve.js +24 -42
  98. package/lib/vendor/blamejs/lib/guard-managesieve-command.js +17 -31
  99. package/lib/vendor/blamejs/lib/guard-markdown.js +37 -104
  100. package/lib/vendor/blamejs/lib/guard-message-id.js +26 -45
  101. package/lib/vendor/blamejs/lib/guard-mime.js +39 -151
  102. package/lib/vendor/blamejs/lib/guard-oauth.js +54 -135
  103. package/lib/vendor/blamejs/lib/guard-pdf.js +45 -101
  104. package/lib/vendor/blamejs/lib/guard-pop3-command.js +21 -31
  105. package/lib/vendor/blamejs/lib/guard-posture-chain.js +24 -42
  106. package/lib/vendor/blamejs/lib/guard-regex.js +33 -107
  107. package/lib/vendor/blamejs/lib/guard-saga-config.js +24 -42
  108. package/lib/vendor/blamejs/lib/guard-shell.js +42 -172
  109. package/lib/vendor/blamejs/lib/guard-smtp-command.js +48 -54
  110. package/lib/vendor/blamejs/lib/guard-snapshot-envelope.js +24 -42
  111. package/lib/vendor/blamejs/lib/guard-sql.js +1491 -0
  112. package/lib/vendor/blamejs/lib/guard-stream-args.js +24 -43
  113. package/lib/vendor/blamejs/lib/guard-svg.js +47 -65
  114. package/lib/vendor/blamejs/lib/guard-template.js +35 -172
  115. package/lib/vendor/blamejs/lib/guard-tenant-id.js +26 -45
  116. package/lib/vendor/blamejs/lib/guard-time.js +32 -154
  117. package/lib/vendor/blamejs/lib/guard-trace-context.js +25 -44
  118. package/lib/vendor/blamejs/lib/guard-uuid.js +32 -153
  119. package/lib/vendor/blamejs/lib/guard-xml.js +38 -113
  120. package/lib/vendor/blamejs/lib/guard-yaml.js +51 -163
  121. package/lib/vendor/blamejs/lib/http-client.js +37 -9
  122. package/lib/vendor/blamejs/lib/inbox.js +120 -107
  123. package/lib/vendor/blamejs/lib/legal-hold.js +121 -50
  124. package/lib/vendor/blamejs/lib/log-stream-cloudwatch.js +47 -31
  125. package/lib/vendor/blamejs/lib/log-stream-otlp.js +32 -18
  126. package/lib/vendor/blamejs/lib/mail-auth.js +236 -0
  127. package/lib/vendor/blamejs/lib/mail-crypto-smime.js +2 -6
  128. package/lib/vendor/blamejs/lib/mail-dkim.js +1 -0
  129. package/lib/vendor/blamejs/lib/mail-greylist.js +2 -6
  130. package/lib/vendor/blamejs/lib/mail-helo.js +2 -6
  131. package/lib/vendor/blamejs/lib/mail-journal.js +85 -64
  132. package/lib/vendor/blamejs/lib/mail-rbl.js +2 -6
  133. package/lib/vendor/blamejs/lib/mail-scan.js +2 -6
  134. package/lib/vendor/blamejs/lib/mail-server-jmap.js +117 -12
  135. package/lib/vendor/blamejs/lib/mail-server-mx.js +276 -7
  136. package/lib/vendor/blamejs/lib/mail-spam-score.js +2 -6
  137. package/lib/vendor/blamejs/lib/mail-store.js +293 -154
  138. package/lib/vendor/blamejs/lib/mail.js +8 -4
  139. package/lib/vendor/blamejs/lib/middleware/body-parser.js +71 -25
  140. package/lib/vendor/blamejs/lib/middleware/csrf-protect.js +19 -8
  141. package/lib/vendor/blamejs/lib/middleware/dpop.js +10 -1
  142. package/lib/vendor/blamejs/lib/middleware/fetch-metadata.js +17 -7
  143. package/lib/vendor/blamejs/lib/middleware/idempotency-key.js +75 -51
  144. package/lib/vendor/blamejs/lib/middleware/rate-limit.js +102 -32
  145. package/lib/vendor/blamejs/lib/middleware/security-headers.js +21 -5
  146. package/lib/vendor/blamejs/lib/migrations.js +108 -66
  147. package/lib/vendor/blamejs/lib/network-heartbeat.js +7 -0
  148. package/lib/vendor/blamejs/lib/network-proxy.js +24 -1
  149. package/lib/vendor/blamejs/lib/nonce-store.js +31 -9
  150. package/lib/vendor/blamejs/lib/object-store/azure-blob-bucket-ops.js +9 -4
  151. package/lib/vendor/blamejs/lib/object-store/azure-blob.js +57 -3
  152. package/lib/vendor/blamejs/lib/object-store/gcs.js +4 -1
  153. package/lib/vendor/blamejs/lib/object-store/sigv4-bucket-ops.js +5 -2
  154. package/lib/vendor/blamejs/lib/object-store/sigv4.js +38 -6
  155. package/lib/vendor/blamejs/lib/observability-otlp-exporter.js +9 -1
  156. package/lib/vendor/blamejs/lib/observability.js +124 -0
  157. package/lib/vendor/blamejs/lib/otel-export.js +12 -3
  158. package/lib/vendor/blamejs/lib/outbox.js +184 -83
  159. package/lib/vendor/blamejs/lib/parsers/safe-xml.js +47 -7
  160. package/lib/vendor/blamejs/lib/pqc-agent.js +44 -0
  161. package/lib/vendor/blamejs/lib/pubsub-cluster.js +42 -20
  162. package/lib/vendor/blamejs/lib/queue-local.js +225 -140
  163. package/lib/vendor/blamejs/lib/queue-redis.js +9 -1
  164. package/lib/vendor/blamejs/lib/queue-sqs.js +6 -0
  165. package/lib/vendor/blamejs/lib/queue.js +7 -0
  166. package/lib/vendor/blamejs/lib/redact.js +68 -11
  167. package/lib/vendor/blamejs/lib/redis-client.js +160 -31
  168. package/lib/vendor/blamejs/lib/request-helpers.js +7 -0
  169. package/lib/vendor/blamejs/lib/retention.js +117 -42
  170. package/lib/vendor/blamejs/lib/router.js +212 -5
  171. package/lib/vendor/blamejs/lib/safe-dns.js +29 -45
  172. package/lib/vendor/blamejs/lib/safe-ical.js +18 -33
  173. package/lib/vendor/blamejs/lib/safe-icap.js +27 -43
  174. package/lib/vendor/blamejs/lib/safe-sieve.js +21 -40
  175. package/lib/vendor/blamejs/lib/safe-sql.js +212 -3
  176. package/lib/vendor/blamejs/lib/safe-url.js +170 -3
  177. package/lib/vendor/blamejs/lib/safe-vcard.js +18 -33
  178. package/lib/vendor/blamejs/lib/scheduler.js +47 -12
  179. package/lib/vendor/blamejs/lib/seeders.js +122 -74
  180. package/lib/vendor/blamejs/lib/session-stores.js +42 -14
  181. package/lib/vendor/blamejs/lib/session.js +175 -77
  182. package/lib/vendor/blamejs/lib/sql.js +3842 -0
  183. package/lib/vendor/blamejs/lib/sse.js +26 -0
  184. package/lib/vendor/blamejs/lib/ssrf-guard.js +169 -4
  185. package/lib/vendor/blamejs/lib/static.js +177 -34
  186. package/lib/vendor/blamejs/lib/subject.js +96 -49
  187. package/lib/vendor/blamejs/lib/vault/index.js +3 -2
  188. package/lib/vendor/blamejs/lib/vault/passphrase-ops.js +3 -2
  189. package/lib/vendor/blamejs/lib/vault/rotate.js +168 -108
  190. package/lib/vendor/blamejs/lib/vault-aad.js +6 -0
  191. package/lib/vendor/blamejs/lib/vendor-data.js +2 -0
  192. package/lib/vendor/blamejs/lib/websocket.js +35 -5
  193. package/lib/vendor/blamejs/lib/worker-pool.js +11 -0
  194. package/lib/vendor/blamejs/package.json +2 -2
  195. package/lib/vendor/blamejs/release-notes/v0.14.x.json +1503 -0
  196. package/lib/vendor/blamejs/release-notes/v0.15.0.json +77 -0
  197. package/lib/vendor/blamejs/release-notes/v0.15.1.json +22 -0
  198. package/lib/vendor/blamejs/release-notes/v0.15.2.json +22 -0
  199. package/lib/vendor/blamejs/release-notes/v0.15.3.json +39 -0
  200. package/lib/vendor/blamejs/release-notes/v0.15.4.json +39 -0
  201. package/lib/vendor/blamejs/release-notes/v0.15.5.json +22 -0
  202. package/lib/vendor/blamejs/release-notes/v0.15.6.json +59 -0
  203. package/lib/vendor/blamejs/release-notes/v0.15.7.json +43 -0
  204. package/lib/vendor/blamejs/scripts/check-services.js +21 -0
  205. package/lib/vendor/blamejs/scripts/gen-migrating.js +67 -0
  206. package/lib/vendor/blamejs/scripts/release.js +398 -38
  207. package/lib/vendor/blamejs/test/00-primitives.js +168 -0
  208. package/lib/vendor/blamejs/test/10-state.js +140 -14
  209. package/lib/vendor/blamejs/test/20-db.js +65 -2
  210. package/lib/vendor/blamejs/test/helpers/db.js +9 -0
  211. package/lib/vendor/blamejs/test/helpers/drivers.js +27 -15
  212. package/lib/vendor/blamejs/test/helpers/services.js +21 -0
  213. package/lib/vendor/blamejs/test/integration/audit-actor-binding-pg.test.js +246 -0
  214. package/lib/vendor/blamejs/test/integration/audit-chain-external-db.test.js +517 -0
  215. package/lib/vendor/blamejs/test/integration/audit-stack-mysql.test.js +639 -0
  216. package/lib/vendor/blamejs/test/integration/audit-stack-postgres.test.js +832 -0
  217. package/lib/vendor/blamejs/test/integration/backup-restore-objectstore.test.js +453 -0
  218. package/lib/vendor/blamejs/test/integration/data-layer-cluster-mysql.test.js +649 -0
  219. package/lib/vendor/blamejs/test/integration/data-layer-cluster-pg.test.js +770 -0
  220. package/lib/vendor/blamejs/test/integration/data-layer-mysql-privacy.test.js +630 -0
  221. package/lib/vendor/blamejs/test/integration/data-layer-mysql.test.js +610 -0
  222. package/lib/vendor/blamejs/test/integration/data-layer-pg.test.js +577 -0
  223. package/lib/vendor/blamejs/test/integration/data-layer-postgres.test.js +771 -0
  224. package/lib/vendor/blamejs/test/integration/db-layer-mysql.test.js +549 -0
  225. package/lib/vendor/blamejs/test/integration/db-layer-postgres.test.js +598 -0
  226. package/lib/vendor/blamejs/test/integration/distributed-scheduler-fencing-pg.test.js +602 -0
  227. package/lib/vendor/blamejs/test/integration/external-db-postgres.test.js +576 -0
  228. package/lib/vendor/blamejs/test/integration/framework-schema-mysql.test.js +353 -0
  229. package/lib/vendor/blamejs/test/integration/log-stream-cloudwatch.test.js +224 -0
  230. package/lib/vendor/blamejs/test/integration/mail-crypto-smime.test.js +142 -17
  231. package/lib/vendor/blamejs/test/integration/network-heartbeat.test.js +25 -10
  232. package/lib/vendor/blamejs/test/integration/object-store-azure.test.js +101 -0
  233. package/lib/vendor/blamejs/test/integration/object-store-gcs.test.js +239 -0
  234. package/lib/vendor/blamejs/test/integration/object-store-sigv4.test.js +35 -16
  235. package/lib/vendor/blamejs/test/integration/object-store-worm-lock.test.js +291 -0
  236. package/lib/vendor/blamejs/test/integration/pubsub.test.js +14 -0
  237. package/lib/vendor/blamejs/test/integration/queue-sqs.test.js +322 -0
  238. package/lib/vendor/blamejs/test/integration/redis-reconnect-toxiproxy.test.js +300 -0
  239. package/lib/vendor/blamejs/test/integration/sql-fts5-catalog-sqlite.test.js +154 -0
  240. package/lib/vendor/blamejs/test/integration/tls-classical-downgrade-audit.test.js +71 -0
  241. package/lib/vendor/blamejs/test/layer-0-primitives/agent-event-bus.test.js +175 -12
  242. package/lib/vendor/blamejs/test/layer-0-primitives/atomic-file-exclusive-temp.test.js +216 -0
  243. package/lib/vendor/blamejs/test/layer-0-primitives/audit-checkpoint-false-rollback.test.js +203 -0
  244. package/lib/vendor/blamejs/test/layer-0-primitives/audit-query-self-log.test.js +126 -0
  245. package/lib/vendor/blamejs/test/layer-0-primitives/audit-safeemit-redacts-secrets.test.js +196 -0
  246. package/lib/vendor/blamejs/test/layer-0-primitives/audit-signing-key-rotation.test.js +197 -0
  247. package/lib/vendor/blamejs/test/layer-0-primitives/audit-verifybundle-tamper.test.js +209 -0
  248. package/lib/vendor/blamejs/test/layer-0-primitives/azure-blob-key-encoding.test.js +121 -0
  249. package/lib/vendor/blamejs/test/layer-0-primitives/backup-residency-posture.test.js +168 -0
  250. package/lib/vendor/blamejs/test/layer-0-primitives/backup-scheduletest-drill.test.js +318 -0
  251. package/lib/vendor/blamejs/test/layer-0-primitives/break-glass.test.js +233 -7
  252. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +1196 -14
  253. package/lib/vendor/blamejs/test/layer-0-primitives/compliance.test.js +229 -0
  254. package/lib/vendor/blamejs/test/layer-0-primitives/credential-hash.test.js +18 -0
  255. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-derived-hash.test.js +24 -7
  256. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-dual-read-migrate.test.js +165 -0
  257. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-per-row-key.test.js +350 -0
  258. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-unseal-rate-cap.test.js +27 -9
  259. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-field-upgrade-dialect.test.js +76 -0
  260. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-interop-oracles.test.js +392 -0
  261. package/lib/vendor/blamejs/test/layer-0-primitives/csrf-protect.test.js +159 -0
  262. package/lib/vendor/blamejs/test/layer-0-primitives/db-column-gate.test.js +180 -1
  263. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-cross-schema.test.js +5 -2
  264. package/lib/vendor/blamejs/test/layer-0-primitives/db-query-sealed-field-in.test.js +101 -0
  265. package/lib/vendor/blamejs/test/layer-0-primitives/db-raw-residency-gate.test.js +128 -0
  266. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-drift.test.js +38 -5
  267. package/lib/vendor/blamejs/test/layer-0-primitives/db-schema-reconcile-emittable.test.js +127 -0
  268. package/lib/vendor/blamejs/test/layer-0-primitives/db-stream-and-payload-shape.test.js +267 -0
  269. package/lib/vendor/blamejs/test/layer-0-primitives/db-worm.test.js +150 -0
  270. package/lib/vendor/blamejs/test/layer-0-primitives/defineguard-default-gate-posture-caps.test.js +30 -0
  271. package/lib/vendor/blamejs/test/layer-0-primitives/dpop-middleware-replaystore-required.test.js +46 -0
  272. package/lib/vendor/blamejs/test/layer-0-primitives/dsr.test.js +218 -0
  273. package/lib/vendor/blamejs/test/layer-0-primitives/erase-posture-vacuum.test.js +210 -0
  274. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-hardening.test.js +4 -1
  275. package/lib/vendor/blamejs/test/layer-0-primitives/external-db-migrate.test.js +48 -2
  276. package/lib/vendor/blamejs/test/layer-0-primitives/federation-vc-suite.test.js +237 -5
  277. package/lib/vendor/blamejs/test/layer-0-primitives/fetch-metadata.test.js +20 -9
  278. package/lib/vendor/blamejs/test/layer-0-primitives/file-upload-content-safety-skip-audit.test.js +193 -0
  279. package/lib/vendor/blamejs/test/layer-0-primitives/guard-csv.test.js +90 -0
  280. package/lib/vendor/blamejs/test/layer-0-primitives/http-client-stream.test.js +85 -0
  281. package/lib/vendor/blamejs/test/layer-0-primitives/idempotency-key.test.js +10 -6
  282. package/lib/vendor/blamejs/test/layer-0-primitives/inbox.test.js +15 -4
  283. package/lib/vendor/blamejs/test/layer-0-primitives/legal-hold.test.js +146 -0
  284. package/lib/vendor/blamejs/test/layer-0-primitives/mail-auth.test.js +189 -0
  285. package/lib/vendor/blamejs/test/layer-0-primitives/mail-journal.test.js +3 -1
  286. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-jmap.test.js +123 -4
  287. package/lib/vendor/blamejs/test/layer-0-primitives/mail-server-mx.test.js +207 -2
  288. package/lib/vendor/blamejs/test/layer-0-primitives/mail-store.test.js +74 -0
  289. package/lib/vendor/blamejs/test/layer-0-primitives/oauth-callback.test.js +43 -0
  290. package/lib/vendor/blamejs/test/layer-0-primitives/otel-export.test.js +133 -0
  291. package/lib/vendor/blamejs/test/layer-0-primitives/otlp-attr-redaction.test.js +101 -0
  292. package/lib/vendor/blamejs/test/layer-0-primitives/outbox-inflight-reaper.test.js +136 -0
  293. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-standalone.test.js +83 -0
  294. package/lib/vendor/blamejs/test/layer-0-primitives/passkey-real-vectors.test.js +429 -0
  295. package/lib/vendor/blamejs/test/layer-0-primitives/pqc-agent-curve.test.js +21 -11
  296. package/lib/vendor/blamejs/test/layer-0-primitives/queue-byo-db.test.js +40 -0
  297. package/lib/vendor/blamejs/test/layer-0-primitives/redact-dlp.test.js +83 -0
  298. package/lib/vendor/blamejs/test/layer-0-primitives/redis-client.test.js +113 -0
  299. package/lib/vendor/blamejs/test/layer-0-primitives/retention-dryrun-no-vacuum.test.js +99 -0
  300. package/lib/vendor/blamejs/test/layer-0-primitives/retention-floor.test.js +59 -0
  301. package/lib/vendor/blamejs/test/layer-0-primitives/router-use-path-scope.test.js +255 -0
  302. package/lib/vendor/blamejs/test/layer-0-primitives/safe-url-canonicalize.test.js +362 -0
  303. package/lib/vendor/blamejs/test/layer-0-primitives/safe-xml.test.js +143 -0
  304. package/lib/vendor/blamejs/test/layer-0-primitives/saml-subjectconfirmation-notonorafter.test.js +287 -0
  305. package/lib/vendor/blamejs/test/layer-0-primitives/scheduler-watchdog-stale-settle.test.js +71 -0
  306. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc-ecdsa-p1363.test.js +79 -0
  307. package/lib/vendor/blamejs/test/layer-0-primitives/sd-jwt-vc.test.js +50 -0
  308. package/lib/vendor/blamejs/test/layer-0-primitives/security-headers.test.js +31 -4
  309. package/lib/vendor/blamejs/test/layer-0-primitives/session-extensions.test.js +45 -0
  310. package/lib/vendor/blamejs/test/layer-0-primitives/sigv4-bucket-ops.test.js +49 -0
  311. package/lib/vendor/blamejs/test/layer-0-primitives/sql.test.js +595 -0
  312. package/lib/vendor/blamejs/test/layer-0-primitives/sse-backpressure.test.js +91 -0
  313. package/lib/vendor/blamejs/test/layer-0-primitives/ssrf-guard.test.js +69 -0
  314. package/lib/vendor/blamejs/test/layer-0-primitives/static.test.js +194 -2
  315. package/lib/vendor/blamejs/test/layer-0-primitives/websocket-extension-header.test.js +88 -0
  316. package/lib/vendor/blamejs/test/layer-0-primitives/worker-pool-recycle-race.test.js +66 -0
  317. package/lib/vendor/blamejs/test/layer-1-state/api-key.test.js +84 -0
  318. package/lib/vendor/blamejs/test/layer-5-integration/external-db-residency.test.js +638 -0
  319. package/lib/vendor/blamejs/test/layer-5-integration/guard-host-integration.test.js +21 -0
  320. package/lib/vendor/blamejs/test/smoke.js +79 -21
  321. package/package.json +2 -2
  322. package/lib/vendor/blamejs/release-notes/v0.14.0.json +0 -43
  323. package/lib/vendor/blamejs/release-notes/v0.14.1.json +0 -60
  324. package/lib/vendor/blamejs/release-notes/v0.14.10.json +0 -54
  325. package/lib/vendor/blamejs/release-notes/v0.14.11.json +0 -72
  326. package/lib/vendor/blamejs/release-notes/v0.14.12.json +0 -95
  327. package/lib/vendor/blamejs/release-notes/v0.14.13.json +0 -52
  328. package/lib/vendor/blamejs/release-notes/v0.14.14.json +0 -31
  329. package/lib/vendor/blamejs/release-notes/v0.14.16.json +0 -45
  330. package/lib/vendor/blamejs/release-notes/v0.14.17.json +0 -57
  331. package/lib/vendor/blamejs/release-notes/v0.14.18.json +0 -127
  332. package/lib/vendor/blamejs/release-notes/v0.14.19.json +0 -61
  333. package/lib/vendor/blamejs/release-notes/v0.14.2.json +0 -18
  334. package/lib/vendor/blamejs/release-notes/v0.14.20.json +0 -73
  335. package/lib/vendor/blamejs/release-notes/v0.14.21.json +0 -98
  336. package/lib/vendor/blamejs/release-notes/v0.14.22.json +0 -91
  337. package/lib/vendor/blamejs/release-notes/v0.14.3.json +0 -18
  338. package/lib/vendor/blamejs/release-notes/v0.14.4.json +0 -18
  339. package/lib/vendor/blamejs/release-notes/v0.14.5.json +0 -18
  340. package/lib/vendor/blamejs/release-notes/v0.14.6.json +0 -60
  341. package/lib/vendor/blamejs/release-notes/v0.14.7.json +0 -77
  342. package/lib/vendor/blamejs/release-notes/v0.14.8.json +0 -27
  343. package/lib/vendor/blamejs/release-notes/v0.14.9.json +0 -40
@@ -309,6 +309,7 @@ function _redact(value, depth, maxDepth, marker, parentKey) {
309
309
  function _resetForTest() {
310
310
  sensitiveFieldsSet = new Set(SENSITIVE_FIELDS);
311
311
  customDetectors = [];
312
+ outboundInstallCount = 0;
312
313
  }
313
314
 
314
315
  // ---- Classifier presets (for outbound DLP) ----
@@ -625,6 +626,14 @@ function classifyDefaults(opts) {
625
626
 
626
627
  var OUTBOUND_INSTALL_REGISTRY = new WeakMap();
627
628
 
629
+ // Count of primitive instances currently wrapped by an outbound-DLP
630
+ // interceptor. A WeakMap can't be enumerated, so this counter is the
631
+ // cheap "is anything installed?" signal b.compliance.set reads to decide
632
+ // whether to warn that a DLP-floor posture was pinned without wiring.
633
+ // Incremented per primitive on install, decremented on uninstall; never
634
+ // negative.
635
+ var outboundInstallCount = 0;
636
+
628
637
  function _emitDlp(action, outcome, metadata) {
629
638
  try {
630
639
  audit().safeEmit({
@@ -740,15 +749,15 @@ function installOutboundDlp(opts) {
740
749
 
741
750
  if (opts.httpClient) {
742
751
  var u1 = _installHttpClient(opts.httpClient, classifier, opts);
743
- if (u1) { uninstallers.push(u1); installed.httpClient = true; }
752
+ if (u1) { uninstallers.push(u1); installed.httpClient = true; outboundInstallCount += 1; }
744
753
  }
745
754
  if (opts.mail) {
746
755
  var u2 = _installMail(opts.mail, classifier, opts);
747
- if (u2) { uninstallers.push(u2); installed.mail = true; }
756
+ if (u2) { uninstallers.push(u2); installed.mail = true; outboundInstallCount += 1; }
748
757
  }
749
758
  if (opts.webhook) {
750
759
  var u3 = _installWebhook(opts.webhook, classifier, opts);
751
- if (u3) { uninstallers.push(u3); installed.webhook = true; }
760
+ if (u3) { uninstallers.push(u3); installed.webhook = true; outboundInstallCount += 1; }
752
761
  }
753
762
 
754
763
  _emitDlp("dlp.outbound.installed", "success", {
@@ -761,12 +770,37 @@ function installOutboundDlp(opts) {
761
770
  uninstall: function () {
762
771
  while (uninstallers.length > 0) {
763
772
  var fn = uninstallers.pop();
764
- try { fn(); } catch (_e) { /* best-effort */ }
773
+ try { fn(); if (outboundInstallCount > 0) outboundInstallCount -= 1; }
774
+ catch (_e) { /* best-effort */ }
765
775
  }
766
776
  },
767
777
  };
768
778
  }
769
779
 
780
+ /**
781
+ * @primitive b.redact.isOutboundDlpInstalled
782
+ * @signature b.redact.isOutboundDlpInstalled()
783
+ * @since 0.14.27
784
+ * @compliance hipaa, pci-dss, gdpr, soc2, fapi2
785
+ * @related b.redact.installForPosture, b.redact.installOutboundDlp
786
+ *
787
+ * Returns `true` when at least one primitive instance (httpClient /
788
+ * mail / webhook) currently carries an outbound-DLP interceptor.
789
+ * `b.compliance.set` reads this to decide whether to emit the one-time
790
+ * `compliance.posture.outbound_dlp_unwired` warning when a posture whose
791
+ * floor implies outbound DLP is pinned without any wiring. Read-only.
792
+ *
793
+ * @example
794
+ * b.redact.isOutboundDlpInstalled(); // → false
795
+ * var dlp = b.redact.installForPosture("hipaa", { httpClient: myHttp });
796
+ * b.redact.isOutboundDlpInstalled(); // → true
797
+ * dlp.uninstall();
798
+ * b.redact.isOutboundDlpInstalled(); // → false
799
+ */
800
+ function isOutboundDlpInstalled() {
801
+ return outboundInstallCount > 0;
802
+ }
803
+
770
804
  function _resolvePosturePatterns(name) {
771
805
  var n = String(name).toLowerCase();
772
806
  if (n === "pci-dss" || n === "pci") {
@@ -779,6 +813,15 @@ function _resolvePosturePatterns(name) {
779
813
  return ["pan", "credit-card", "iban", "pem", "aws-access-key", "jwt", "api-key-shape"];
780
814
  }
781
815
  if (n === "soc2" || n === "gdpr") {
816
+ // Known fidelity collapse: soc2 and gdpr share one outbound-DLP
817
+ // pattern set here. They are distinct regimes — GDPR's special-
818
+ // category personal data (Art. 9) is broader than the SOC 2 Trust
819
+ // Services criteria this preset targets — but the built-in
820
+ // value-shape detectors don't yet distinguish them, so the same
821
+ // pattern list backs both. Operators needing GDPR-specific shapes
822
+ // pass an explicit classifier (classifyDefaults) rather than the
823
+ // posture preset. This is intentional, not an accidental alias —
824
+ // documented so it isn't mistaken for per-regime handling.
782
825
  return ["ssn", "ein", "pem", "ssh-private", "aws-access-key", "api-key-shape"];
783
826
  }
784
827
  throw new DlpError("redact-dlp/unknown-posture",
@@ -959,9 +1002,12 @@ function _summarizeHit(h) {
959
1002
  return { label: h.label, action: h.action, where: h.where };
960
1003
  }
961
1004
 
962
- // Posture-coordinated install — a thin wrapper used by b.compliance.set
963
- // to wire DLP automatically when the posture is set. Operators using
964
- // b.compliance can rely on this; direct callers use installOutboundDlp.
1005
+ // Posture-coordinated install — the operator passes the primitive
1006
+ // instances to wire (httpClient / mail / webhook); the posture name
1007
+ // selects the default classifier. b.compliance.set does NOT call this:
1008
+ // it holds no httpClient / mail / webhook handles, so it cannot install
1009
+ // outbound interceptors. Operators wire DLP explicitly by calling this
1010
+ // (or installOutboundDlp) with their own primitive instances.
965
1011
  /**
966
1012
  * @primitive b.redact.installForPosture
967
1013
  * @signature b.redact.installForPosture(posture, primitives)
@@ -970,10 +1016,20 @@ function _summarizeHit(h) {
970
1016
  * @compliance hipaa, pci-dss, gdpr, soc2, fapi2
971
1017
  * @related b.redact.installOutboundDlp, b.redact.classifyDefaults
972
1018
  *
973
- * Posture-coordinated install — a thin wrapper used by
974
- * `b.compliance.set` so picking a posture also wires outbound DLP
975
- * automatically. Direct callers usually want `installOutboundDlp`
976
- * because it accepts the full hook surface.
1019
+ * Posture-coordinated install — picks the default classifier for
1020
+ * `posture` and wraps the operator-supplied `primitives.httpClient` /
1021
+ * `.mail` / `.webhook` so every outbound payload runs through it. A
1022
+ * thin convenience over `installOutboundDlp`; direct callers usually
1023
+ * want `installOutboundDlp` because it accepts the full hook surface.
1024
+ *
1025
+ * The operator MUST call this with the primitive instances — pinning a
1026
+ * posture via `b.compliance.set` does NOT auto-install outbound DLP,
1027
+ * because the compliance coordinator holds no httpClient / mail /
1028
+ * webhook handles. When a posture whose floor implies outbound DLP
1029
+ * (hipaa / pci-dss / gdpr / soc2 / fapi-2.0) is pinned without this
1030
+ * call, `b.compliance.set` emits a one-time
1031
+ * `compliance.posture.outbound_dlp_unwired` audit warning so the gap is
1032
+ * grep-able in the audit chain.
977
1033
  *
978
1034
  * @example
979
1035
  * var dlp = b.redact.installForPosture("hipaa", {
@@ -999,6 +1055,7 @@ module.exports = {
999
1055
  classifyDefaults: classifyDefaults,
1000
1056
  installOutboundDlp: installOutboundDlp,
1001
1057
  installForPosture: installForPosture,
1058
+ isOutboundDlpInstalled: isOutboundDlpInstalled,
1002
1059
  CLASSIFIER_PATTERNS: CLASSIFIER_PATTERNS,
1003
1060
  MARKER: DEFAULT_MARKER,
1004
1061
  SENSITIVE_FIELDS: SENSITIVE_FIELDS,
@@ -28,7 +28,6 @@ var net = require("node:net");
28
28
  var nodeTls = require("node:tls");
29
29
  var nodeUrl = require("node:url");
30
30
  var C = require("./constants");
31
- var safeAsync = require("./safe-async");
32
31
  var validateOpts = require("./validate-opts");
33
32
  var ipUtils = require("./ip-utils");
34
33
  var { RedisError } = require("./framework-error");
@@ -215,11 +214,28 @@ function create(opts) {
215
214
  var connected = false;
216
215
  var connecting = false;
217
216
  var closing = false;
217
+ // Shared in-flight connect. Every _connect() call returns the SAME
218
+ // promise while a connect is in progress, so concurrent callers all
219
+ // observe the same resolve/reject instead of polling a flag. It is
220
+ // ALWAYS settled (resolve on ready, reject on socket-error / connect-
221
+ // timeout / AUTH-or-SELECT failure) and cleared the moment it settles
222
+ // so the next caller starts a fresh attempt — a connect that fails
223
+ // can never leave a never-settling promise behind for the next
224
+ // awaiter to wedge on.
225
+ var connectPromise = null;
218
226
  // Tracked + unref'd reconnect timer. Tracked so close() can cancel a
219
227
  // pending backoff (otherwise a reconnect scheduled before close fires
220
228
  // after it and opens a fresh socket); unref'd so a backoff window doesn't
221
229
  // by itself keep the event loop alive (the process-won't-exit class).
230
+ // Single-flight: a non-null reconnectTimer means a backoff is already
231
+ // pending — socket-error AND socket-close firing for the same failure
232
+ // must not stack two timers (which would burn the reconnect budget at
233
+ // 2x and open redundant sockets).
222
234
  var reconnectTimer = null;
235
+ // Set once the reconnect budget is exhausted. Makes the give-up path
236
+ // idempotent (drains pending+backlog exactly once) and stops a stray
237
+ // close/error after give-up from re-draining or racing a later success.
238
+ var gaveUp = false;
223
239
  var rxBuffer = Buffer.alloc(0);
224
240
  // FIFO of in-flight commands awaiting a response
225
241
  var pending = [];
@@ -239,18 +255,31 @@ function create(opts) {
239
255
 
240
256
  function _scheduleReconnect() {
241
257
  if (closing) return;
258
+ // Single-flight: a socket failure surfaces as both an `error` and a
259
+ // `close` event. Without this guard each one schedules its own timer,
260
+ // stacking two reconnects for one failure — the budget burns at 2x
261
+ // and two fresh sockets open. A pending backoff already covers the
262
+ // failure, so a second call is a no-op.
263
+ if (reconnectTimer !== null) return;
242
264
  if (maxReconnectAttempts >= 0 && reconnectAttempt >= maxReconnectAttempts) {
243
- // Drain pending callbacks with a clear error
265
+ // Reconnect budget exhausted. Drain pending + backlog exactly once;
266
+ // a later stray close/error must not re-drain or race a future
267
+ // success path.
268
+ if (gaveUp) return;
269
+ gaveUp = true;
244
270
  var err = _err("RECONNECT_GAVE_UP",
245
271
  "redis: gave up after " + reconnectAttempt + " reconnect attempts");
246
272
  _drainPending(err);
247
273
  return;
248
274
  }
249
275
  reconnectAttempt++;
276
+ // Exponential backoff capped at 30s. Base 100ms is the first-retry
277
+ // delay (not a duration unit), so it stays a literal; the cap routes
278
+ // through C.TIME.
250
279
  var delay = Math.min(C.TIME.seconds(30), 100 * Math.pow(2, reconnectAttempt - 1));
251
280
  reconnectTimer = setTimeout(function () {
252
281
  reconnectTimer = null;
253
- _connect().catch(function () { /* will reschedule */ });
282
+ _connect().catch(function () { /* failure reschedules via the teardown path */ });
254
283
  }, delay);
255
284
  if (typeof reconnectTimer.unref === "function") reconnectTimer.unref();
256
285
  }
@@ -261,7 +290,10 @@ function create(opts) {
261
290
  batch.forEach(function (p) { p.reject(err); });
262
291
  var bl = backlog.slice();
263
292
  backlog.length = 0;
264
- bl.forEach(function (p) { p.reject(err); });
293
+ bl.forEach(function (p) {
294
+ if (p.timer) { clearTimeout(p.timer); p.timer = null; }
295
+ p.reject(err);
296
+ });
265
297
  }
266
298
 
267
299
  function _onData(chunk) {
@@ -312,39 +344,74 @@ function create(opts) {
312
344
  }
313
345
  }
314
346
 
315
- function _onSocketError(err) {
316
- var werr = _err("SOCKET", "redis socket error: " + ((err && err.message) || String(err)));
317
- _drainPending(werr);
347
+ // Single teardown path for a lost socket. A failure surfaces as an
348
+ // `error` event AND a `close` event (and `error` then destroys the
349
+ // socket, which fires `close` again) — three callbacks for ONE lost
350
+ // connection. Routing all of them here, guarded by a "are we still
351
+ // attached to this socket" check, means pending is drained once and
352
+ // exactly one reconnect is scheduled (the single-flight guard in
353
+ // _scheduleReconnect absorbs the rest). `err` is the diagnostic to
354
+ // reject in-flight commands with.
355
+ function _teardownSocket(err) {
356
+ // Already torn down for this socket (the sibling event already ran).
357
+ if (!connected && socket === null) {
358
+ // Still let a stray event re-arm a reconnect if one isn't pending
359
+ // and we haven't been closed — but never re-drain pending.
360
+ if (!closing) _scheduleReconnect();
361
+ return;
362
+ }
318
363
  connected = false;
319
- try { if (socket) socket.destroy(); } catch (_e) { /* best-effort socket teardown */ }
364
+ var dead = socket;
320
365
  socket = null;
366
+ if (dead) {
367
+ try {
368
+ dead.removeListener("error", _onSocketError);
369
+ dead.removeListener("close", _onSocketClose);
370
+ dead.removeListener("data", _onData);
371
+ dead.destroy();
372
+ } catch (_e) { /* best-effort socket teardown */ }
373
+ }
374
+ _drainPending(err);
321
375
  if (!closing) _scheduleReconnect();
322
376
  }
323
377
 
378
+ function _onSocketError(err) {
379
+ _teardownSocket(_err("SOCKET",
380
+ "redis socket error: " + ((err && err.message) || String(err))));
381
+ }
382
+
324
383
  function _onSocketClose() {
325
- connected = false;
326
- if (!closing) {
327
- var err = _err("SOCKET_CLOSED", "redis socket closed unexpectedly");
328
- _drainPending(err);
329
- socket = null;
330
- _scheduleReconnect();
331
- }
384
+ _teardownSocket(_err("SOCKET_CLOSED", "redis socket closed unexpectedly"));
332
385
  }
333
386
 
334
- async function _connect() {
335
- // A reconnect timer scheduled before close() can still fire afterward;
336
- // refuse to re-open once closing so it doesn't leak a fresh socket.
337
- if (closing) return;
338
- if (connected) return;
339
- if (connecting) {
340
- // Wait until current connect attempt resolves
341
- while (connecting) await safeAsync.sleep(20);
342
- return;
343
- }
387
+ // _connect() — public entry. Returns a promise that ALWAYS settles.
388
+ // Concurrent callers (and the reconnect timer) share the single
389
+ // in-flight connectPromise rather than each starting a parallel dial,
390
+ // and they all observe the same resolve/reject. A previous version
391
+ // polled a `connecting` flag in a `while (connecting) await sleep(20)`
392
+ // loop; if a failure path failed to clear that flag the waiter spun
393
+ // forever. The shared promise removes that wedge — the promise is
394
+ // cleared the instant it settles, so a failed connect can never leave
395
+ // a never-settling promise behind.
396
+ function _connect() {
397
+ if (closing) return Promise.resolve();
398
+ if (connected) return Promise.resolve();
399
+ if (connectPromise) return connectPromise;
400
+ connectPromise = _doConnect();
401
+ // Clear the shared promise once it settles (either way) so the next
402
+ // _connect() starts a fresh attempt instead of re-awaiting a stale
403
+ // settled promise.
404
+ var clear = function () { connectPromise = null; };
405
+ connectPromise.then(clear, clear);
406
+ return connectPromise;
407
+ }
408
+
409
+ async function _doConnect() {
344
410
  connecting = true;
345
411
  rxBuffer = Buffer.alloc(0);
412
+ var newSocket = null;
346
413
  try {
347
- socket = await new Promise(function (resolve, reject) {
414
+ newSocket = await new Promise(function (resolve, reject) {
348
415
  var sock;
349
416
  var timer = setTimeout(function () {
350
417
  try { if (sock) sock.destroy(); } catch (_e) { /* best-effort socket teardown */ }
@@ -371,16 +438,19 @@ function create(opts) {
371
438
  }
372
439
  sock.once("error", onErr);
373
440
  });
441
+ socket = newSocket;
374
442
  socket.setNoDelay(true);
375
443
  socket.on("data", _onData);
376
444
  socket.on("error", _onSocketError);
377
445
  socket.on("close", _onSocketClose);
378
446
  connected = true;
379
- reconnectAttempt = 0;
380
447
 
381
448
  // Auth + select db on (re)connect — without resetting the
382
449
  // backlog of commands queued during disconnect. Send these
383
450
  // BEFORE the backlog so the server is ready when backlog flushes.
451
+ // A failure here (wrong password, server SELECT rejection, socket
452
+ // dropped mid-AUTH) must not leave connected=true on a half-open
453
+ // socket — the catch below tears the socket down and rethrows.
384
454
  if (password) {
385
455
  var authArgs = username ? ["AUTH", username, password] : ["AUTH", password];
386
456
  await _sendNoQueue(authArgs);
@@ -389,15 +459,47 @@ function create(opts) {
389
459
  await _sendNoQueue(["SELECT", String(db)]);
390
460
  }
391
461
 
392
- // Flush backlog
462
+ // Connect fully succeeded — only now reset the backoff counter +
463
+ // the give-up latch so a future disconnect gets a fresh budget.
464
+ reconnectAttempt = 0;
465
+ gaveUp = false;
466
+ connecting = false;
467
+
468
+ // Flush backlog. Clear each queued entry's not-connected timeout
469
+ // before it goes on the wire — the in-flight command timeout in
470
+ // _writeAndAwait now owns its lifetime.
393
471
  var bl = backlog.slice();
394
472
  backlog.length = 0;
395
- bl.forEach(function (entry) { _writeAndAwait(entry.args, entry.resolve, entry.reject); });
473
+ bl.forEach(function (entry) {
474
+ if (entry.timer) { clearTimeout(entry.timer); entry.timer = null; }
475
+ _writeAndAwait(entry.args, entry.resolve, entry.reject);
476
+ });
396
477
  } catch (err) {
397
478
  connecting = false;
479
+ connected = false;
480
+ // Tear down a half-open socket (came up, then AUTH/SELECT failed)
481
+ // so we never leave connected=false with a live socket whose data/
482
+ // error/close handlers would fire against stale state. If the
483
+ // socket-error handler already ran it set socket=null.
484
+ var dead = socket || newSocket;
485
+ socket = null;
486
+ if (dead) {
487
+ try {
488
+ dead.removeListener("error", _onSocketError);
489
+ dead.removeListener("close", _onSocketClose);
490
+ dead.removeListener("data", _onData);
491
+ dead.destroy();
492
+ } catch (_e) { /* best-effort socket teardown */ }
493
+ }
494
+ // A failed dial (reset before ready) or an AUTH/SELECT failure must keep
495
+ // the reconnect loop alive. The post-ready error/close handlers that
496
+ // normally drive reconnect are not attached yet during the dial, so
497
+ // without scheduling here a connection lost mid-dial rejects the connect
498
+ // promise and the client never reconnects. Single-flight + budget-guarded
499
+ // by _scheduleReconnect; the caller still observes this attempt's rejection.
500
+ if (!closing) _scheduleReconnect();
398
501
  throw err;
399
502
  }
400
- connecting = false;
401
503
  }
402
504
 
403
505
  // Internal helper that bypasses the connect-pending backlog (used
@@ -448,7 +550,28 @@ function create(opts) {
448
550
  return;
449
551
  }
450
552
  if (!connected) {
451
- backlog.push({ args: args, resolve: resolve, reject: reject });
553
+ // Reconnect budget exhausted and no reconnect is in flight — a
554
+ // backlogged command here would never be flushed (nothing will
555
+ // reconnect to drain it) and would wedge the caller forever.
556
+ // Reject immediately instead.
557
+ if (gaveUp && reconnectTimer === null && !connecting) {
558
+ reject(_err("RECONNECT_GAVE_UP",
559
+ "redis: client disconnected and reconnect budget exhausted"));
560
+ return;
561
+ }
562
+ // Queued until the next successful connect flushes the backlog.
563
+ // Bound it with a timeout so a connect that never completes (the
564
+ // backend is down for the whole window) settles the caller with
565
+ // a clear error instead of leaving the await pending forever.
566
+ var entry = { args: args, resolve: resolve, reject: reject, timer: null };
567
+ entry.timer = setTimeout(function () {
568
+ var idx = backlog.indexOf(entry);
569
+ if (idx !== -1) backlog.splice(idx, 1);
570
+ reject(_err("COMMAND_TIMEOUT",
571
+ "redis " + args[0] + " timed out while queued (client not connected)"));
572
+ }, commandTimeoutMs);
573
+ if (typeof entry.timer.unref === "function") entry.timer.unref();
574
+ backlog.push(entry);
452
575
  return;
453
576
  }
454
577
  _writeAndAwait(args, resolve, reject);
@@ -469,6 +592,9 @@ function create(opts) {
469
592
  async function close() {
470
593
  closing = true;
471
594
  if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
595
+ // Drop the shared connect promise so a re-create after close (or a
596
+ // late awaiter) doesn't re-await a stale in-flight attempt.
597
+ connectPromise = null;
472
598
  var err = _err("CLOSED", "redis client closed");
473
599
  _drainPending(err);
474
600
  if (socket) {
@@ -492,8 +618,11 @@ function create(opts) {
492
618
  _state: function () {
493
619
  return {
494
620
  connected: connected, closing: closing,
621
+ connecting: connecting,
495
622
  pending: pending.length, backlog: backlog.length,
496
623
  reconnect: reconnectAttempt,
624
+ reconnectPending: reconnectTimer !== null,
625
+ gaveUp: gaveUp,
497
626
  host: host, port: port, db: db, tls: useTls,
498
627
  connectTimeoutMs: connectTimeoutMs,
499
628
  commandTimeoutMs: commandTimeoutMs,
@@ -254,6 +254,13 @@ function clientIp(req, opts) {
254
254
  }
255
255
  if (req.socket && typeof req.socket.remoteAddress === "string") return req.socket.remoteAddress;
256
256
  if (req.connection && typeof req.connection.remoteAddress === "string") return req.connection.remoteAddress;
257
+ // Express-shaped requests expose the resolved client address as `req.ip`
258
+ // (Express derives it from the socket, honoring its own trust-proxy
259
+ // setting) without a `socket.remoteAddress` surface. Fall back to it so a
260
+ // binding captured from such a request is populated rather than null —
261
+ // callers that pin a grant to the issuing IP otherwise capture null and
262
+ // could only be saved by a fail-closed guard at the consumer.
263
+ if (typeof req.ip === "string" && req.ip.length > 0) return req.ip;
257
264
  return null;
258
265
  }
259
266