@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
@@ -0,0 +1,577 @@
1
+ "use strict";
2
+ /**
3
+ * Live data-layer test against the docker Postgres container. Drives the
4
+ * cluster-mode SQL path of the framework's session / cache / nonce /
5
+ * rate-limit primitives end-to-end on a real Postgres server — the path
6
+ * advertised for cluster deployments but which smoke only ever exercises
7
+ * against local SQLite.
8
+ *
9
+ * In cluster mode every one of these primitives composes its SQL through
10
+ * b.sql and dispatches via b.clusterStorage -> b.externalDb -> the
11
+ * operator's Postgres. This test proves:
12
+ *
13
+ * - b.session create / verify / touch / rotate / destroy /
14
+ * destroyAllForUser / count / purgeExpired, with the
15
+ * at-rest sealing (userId/data sealed, userIdHash
16
+ * derived) round-tripping through real Postgres.
17
+ * - b.cache (cluster) get / set (tx upsert + tag) / CAS update /
18
+ * invalidateTag (whereLike prefix) / clear / has /
19
+ * size / getTags.
20
+ * - b.nonceStore (cluster) checkAndInsert (ON CONFLICT DO NOTHING atomic
21
+ * first-seen) + replay rejection + purgeExpired.
22
+ * - b.middleware.rateLimit (cluster) take() = ON CONFLICT increment with
23
+ * a CASE conflict action + RETURNING + the BIGINT
24
+ * count coercing back to a JS number (frameworkSchema
25
+ * COLUMN_TYPES) so count<=limit comparisons are
26
+ * numeric, not string.
27
+ *
28
+ * The "driver" is a persistent docker-exec psql shim (SQL fed over stdin,
29
+ * never argv) modelled on external-db-postgres.test.js. It faithfully
30
+ * reproduces a real node-postgres driver where it matters: BIGINT comes
31
+ * back as a STRING (clusterStorage.execute then coerces it through
32
+ * frameworkSchema.coerceRows), so a counter compared as a string would be
33
+ * caught. The framework tables are created with
34
+ * frameworkSchema.ensureSchema (real DDL, quoted camelCase columns).
35
+ *
36
+ * RUN: node scripts/test-integration.js --skip-service-check data-layer-pg
37
+ */
38
+ var spawn = require("node:child_process").spawn;
39
+ var execFileSync = require("node:child_process").execFileSync;
40
+ var fs = require("node:fs");
41
+ var os = require("node:os");
42
+ var path = require("node:path");
43
+ var helpers = require("../helpers");
44
+ var check = helpers.check;
45
+ var services = require("../helpers/services");
46
+ var b = require("../../");
47
+
48
+ var CONTAINER = "blamejs-test-postgres";
49
+ var NULL_SENTINEL = "__BJNULL__";
50
+
51
+ // Soft assertion: records pass/fail without throwing so every section's
52
+ // findings are collected even when an earlier check fails (one real bug in
53
+ // one primitive shouldn't hide whether the others work on Postgres). All
54
+ // findings are replayed through the hard `check` at the end of run() so the
55
+ // file still FAILS when any contract is unmet.
56
+ var _findings = [];
57
+ function softCheck(label, condition) {
58
+ _findings.push({ label: label, ok: !!condition });
59
+ console.log((condition ? " ok " : " FAIL ") + label);
60
+ }
61
+ var PSQL_ARGS = "psql -U blamejs -d blamejs_test -A " +
62
+ "-v ON_ERROR_STOP=0 -P null=__BJNULL__ 2>&1";
63
+
64
+ // ---- one-shot psql (setup / teardown / out-of-band assertions) ----
65
+ function _psql(sql) {
66
+ var prelude = "\\pset fieldsep '\\t'\n";
67
+ var out = execFileSync(
68
+ "docker",
69
+ ["exec", "-i", CONTAINER, "sh", "-c",
70
+ "psql -U blamejs -d blamejs_test -qtA -P null=__BJNULL__ 2>&1"],
71
+ { input: prelude + sql + "\n", stdio: ["pipe", "pipe", "pipe"] }
72
+ ).toString("utf8");
73
+ if (/^ERROR:/m.test(out)) {
74
+ throw new Error("psql setup failed for [" + sql + "]:\n" + out);
75
+ }
76
+ return out;
77
+ }
78
+
79
+ // ---- persistent-session docker-exec psql driver (faithful to pg) ----
80
+ var _seq = 0;
81
+ function _makeDockerPgDriver() {
82
+ return {
83
+ connect: function () {
84
+ return new Promise(function (resolve, reject) {
85
+ var child = spawn(
86
+ "docker",
87
+ ["exec", "-i", CONTAINER, "sh", "-c",
88
+ PSQL_ARGS + " ; echo __BLAMEJS_PSQL_EXIT__"],
89
+ { stdio: ["pipe", "pipe", "pipe"] }
90
+ );
91
+ var client = { child: child, buf: "", pending: null, closed: false };
92
+ child.on("error", function (e) {
93
+ if (client.pending) { var p = client.pending; client.pending = null; p.reject(e); }
94
+ });
95
+ child.on("close", function () {
96
+ client.closed = true;
97
+ if (client.pending) {
98
+ var p = client.pending; client.pending = null;
99
+ p.reject(new Error("psql session closed mid-statement"));
100
+ }
101
+ });
102
+ child.stdout.on("data", function (chunk) {
103
+ client.buf += chunk.toString("utf8");
104
+ _drain(client);
105
+ });
106
+ var primeSentinel = "__BJ_PRIME__";
107
+ client.pending = {
108
+ sentinel: primeSentinel,
109
+ resolve: function () { resolve(client); },
110
+ reject: reject,
111
+ };
112
+ client.child.stdin.write(
113
+ "\\pset fieldsep '\\t'\n\\pset footer off\n\\set VERBOSITY verbose\n" +
114
+ "\\echo " + primeSentinel + "\n");
115
+ });
116
+ },
117
+
118
+ query: function (client, sql, params) {
119
+ params = params || [];
120
+ var bound = _bindParams(sql, params);
121
+ var sentinel = "__BJ_EOR_" + (++_seq) + "__";
122
+ return new Promise(function (resolve, reject) {
123
+ if (client.closed) { reject(new Error("psql session is closed")); return; }
124
+ client.pending = { sentinel: sentinel, resolve: resolve, reject: reject };
125
+ client.child.stdin.write(bound + "\n;\n\\echo " + sentinel + "\n");
126
+ });
127
+ },
128
+
129
+ close: function (client) {
130
+ return new Promise(function (resolve) {
131
+ if (client.closed) { resolve(); return; }
132
+ try { client.child.stdin.end("\\q\n"); } catch (_e) { /* best effort */ }
133
+ var done = false;
134
+ client.child.on("close", function () { if (!done) { done = true; resolve(); } });
135
+ setTimeout(function () {
136
+ if (done) return;
137
+ done = true;
138
+ try { client.child.kill("SIGKILL"); } catch (_e) {}
139
+ resolve();
140
+ }, 2000);
141
+ });
142
+ },
143
+
144
+ dialect: "postgres",
145
+ };
146
+ }
147
+
148
+ function _drain(client) {
149
+ if (!client.pending) return;
150
+ var sentinel = client.pending.sentinel;
151
+ var marker = "\n" + sentinel + "\n";
152
+ var idx = client.buf.indexOf(marker);
153
+ var startAtZero = client.buf.indexOf(sentinel + "\n") === 0;
154
+ var block;
155
+ if (idx !== -1) {
156
+ block = client.buf.slice(0, idx);
157
+ client.buf = client.buf.slice(idx + marker.length);
158
+ } else if (startAtZero) {
159
+ block = "";
160
+ client.buf = client.buf.slice((sentinel + "\n").length);
161
+ } else {
162
+ return;
163
+ }
164
+ var p = client.pending;
165
+ client.pending = null;
166
+ var parsed;
167
+ try { parsed = _parseBlock(block); }
168
+ catch (e) { return p.reject(e); }
169
+ if (parsed.error) return p.reject(parsed.error);
170
+ p.resolve({ rows: parsed.rows, rowCount: parsed.rowCount });
171
+ }
172
+
173
+ // Inline params: NULL / numbers raw / booleans / single-quote-escaped.
174
+ function _bindParams(sql, params) {
175
+ return sql.replace(/\$(\d+)/g, function (_m, n) {
176
+ var i = Number(n) - 1;
177
+ if (i < 0 || i >= params.length) {
178
+ throw new Error("placeholder $" + n + " has no matching param");
179
+ }
180
+ var v = params[i];
181
+ if (v === null || v === undefined) return "NULL";
182
+ if (typeof v === "number") return String(v);
183
+ if (typeof v === "boolean") return v ? "TRUE" : "FALSE";
184
+ return "'" + String(v).replace(/'/g, "''") + "'";
185
+ });
186
+ }
187
+
188
+ var _CMD_TAG_RE = /^(INSERT|UPDATE|DELETE|MERGE|SELECT|COPY|MOVE)\b(?:\s+\d+)*\s*$/;
189
+ var _CTRL_TAG_RE = /^(BEGIN|COMMIT|ROLLBACK|SET|RESET|SAVEPOINT|RELEASE|START|CREATE|DROP|ALTER|GRANT|REVOKE|TRUNCATE|COMMENT|DO|CALL|VACUUM|ANALYZE|EXPLAIN|TABLE|SHOW|DISCARD)\b/;
190
+
191
+ function _parseBlock(block) {
192
+ var lines = block.split(/\r?\n/);
193
+ while (lines.length && lines[lines.length - 1] === "") lines.pop();
194
+
195
+ for (var i = 0; i < lines.length; i++) {
196
+ var em = /^ERROR:\s+([0-9A-Za-z]{5}):\s*(.*)$/.exec(lines[i]);
197
+ if (em) {
198
+ var err = new Error("Postgres " + em[1] + ": " + em[2]);
199
+ err.code = em[1];
200
+ return { error: err };
201
+ }
202
+ }
203
+
204
+ var affected = null;
205
+ var dataLines = [];
206
+ for (var j = 0; j < lines.length; j++) {
207
+ var ln = lines[j];
208
+ if (/^(NOTICE|WARNING|DETAIL|HINT|LINE|LOCATION|CONTEXT|STATEMENT):/.test(ln)) continue;
209
+ var tm = _CMD_TAG_RE.exec(ln);
210
+ if (tm) {
211
+ var nums = ln.trim().split(/\s+/).slice(1).map(Number);
212
+ if (nums.length) affected = nums[nums.length - 1];
213
+ continue;
214
+ }
215
+ if (_CTRL_TAG_RE.test(ln) && ln.indexOf("\t") === -1) continue;
216
+ dataLines.push(ln);
217
+ }
218
+
219
+ // dataLines carry a header row first (column names AS POSTGRES REPORTS
220
+ // THEM — quoted DDL preserves the camelCase), then data rows. Every cell
221
+ // stays a STRING — exactly the shape node-postgres returns for BIGINT
222
+ // (int8) columns, so clusterStorage's coerceRows is what must turn the
223
+ // framework's int columns back into JS numbers.
224
+ var rows = [];
225
+ if (dataLines.length >= 1) {
226
+ var headers = dataLines[0].split("\t");
227
+ for (var k = 1; k < dataLines.length; k++) {
228
+ var cells = dataLines[k].split("\t");
229
+ var row = {};
230
+ for (var c = 0; c < headers.length; c++) {
231
+ var cell = cells[c];
232
+ row[headers[c]] = (cell === NULL_SENTINEL || cell === undefined) ? null : cell;
233
+ }
234
+ rows.push(row);
235
+ }
236
+ }
237
+ var rowCount = (affected !== null) ? affected : rows.length;
238
+ return { rows: rows, rowCount: rowCount, error: null };
239
+ }
240
+
241
+ // Every framework table frameworkSchema.ensureSchema creates — dropped in
242
+ // setup AND teardown so the run starts clean and leaves the shared test
243
+ // database clean for sibling Postgres tests (which create their own
244
+ // tables). The primitives under test only touch sessions / cache /
245
+ // cache_tags / nonces / rate-limit counters, but ensureSchema materializes
246
+ // the whole framework surface, so all of it is swept.
247
+ var FRAMEWORK_TABLES = [
248
+ "_blamejs_sessions", "_blamejs_cache", "_blamejs_cache_tags",
249
+ "_blamejs_api_encrypt_nonces", "_blamejs_rate_limit_counters",
250
+ "_blamejs_audit_log", "_blamejs_consent_log", "_blamejs_audit_checkpoints",
251
+ "_blamejs_audit_tip", "_blamejs_consent_tip", "_blamejs_audit_purge_anchor",
252
+ "_blamejs_scheduler_ticks", "_blamejs_pubsub_messages", "_blamejs_api_keys",
253
+ "_blamejs_jobs", "_blamejs_seeders", "_blamejs_seeders_lock",
254
+ "_blamejs_break_glass_policies", "_blamejs_break_glass_grants",
255
+ // cluster.init's default DB-row leader-election provider creates these.
256
+ "_blamejs_leader", "_blamejs_cluster_state",
257
+ ];
258
+
259
+ var rateLimitModule = require("../../lib/middleware/rate-limit");
260
+
261
+ async function run() {
262
+ var pg = await services.requireService("postgres");
263
+ if (!pg.ok) throw new Error("postgres unreachable: " + pg.reason);
264
+
265
+ // Drop our framework tables so the run starts clean.
266
+ _psql(FRAMEWORK_TABLES.map(function (t) {
267
+ return "DROP TABLE IF EXISTS " + t + " CASCADE;";
268
+ }).join("\n"));
269
+
270
+ // Full-framework bring-up (vault + db + cryptoField). db.init registers
271
+ // the _blamejs_sessions sealedFields (userId, data) + derived userIdHash,
272
+ // which b.session uses to seal/derive regardless of which backend the SQL
273
+ // routes to. The local SQLite db it opens is unused once cluster mode is
274
+ // active (session SQL dispatches to Postgres) but the cryptoField
275
+ // registry it populates is exactly what session needs.
276
+ var tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "blamejs-datalayer-pg-"));
277
+ await helpers.setupTestDb(tmpDir);
278
+
279
+ var driver = _makeDockerPgDriver();
280
+ b.externalDb._resetForTest();
281
+ b.externalDb.init({
282
+ backends: {
283
+ ops: {
284
+ connect: driver.connect, query: driver.query, close: driver.close,
285
+ dialect: "postgres",
286
+ },
287
+ },
288
+ });
289
+
290
+ // Create the framework tables on real Postgres via the real DDL builder.
291
+ await b.frameworkSchema.ensureSchema({ externalDbBackend: "ops", dialect: "postgres" });
292
+
293
+ // Cluster mode: the framework's session/cache/nonce/rate-limit SQL now
294
+ // routes through clusterStorage -> externalDb -> Postgres. cluster.init
295
+ // runs a boot-time rollback check against the (empty) audit/consent tips
296
+ // ensureSchema just created; with no tip row it skips cleanly.
297
+ await b.cluster.init({
298
+ nodeId: "pg-data-node",
299
+ role: "leader",
300
+ leaseTtl: b.constants.TIME.seconds(30),
301
+ heartbeatInterval: b.constants.TIME.seconds(10),
302
+ externalDbBackend: "ops",
303
+ dialect: "postgres",
304
+ // This node's vault keypair is freshly minted in tmpDir; accept it as
305
+ // the canonical cluster vault key rather than refusing on first boot.
306
+ acceptVaultKeyRotation: true,
307
+ });
308
+ softCheck("cluster is in cluster mode (state routes to Postgres)",
309
+ b.cluster.isClusterMode() === true);
310
+ softCheck("cluster reports leadership on real Postgres", b.cluster.isLeader() === true);
311
+
312
+ try {
313
+ await _section("session", _testSession);
314
+ await _section("cache", _testCacheCluster);
315
+ await _section("nonce", _testNonceCluster);
316
+ await _section("rate-limit", _testRateLimitCluster);
317
+ } finally {
318
+ try { await b.cluster.shutdown(); } catch (_e) {}
319
+ b.cluster._resetForTest();
320
+ try { await b.externalDb.shutdown(); } catch (_e) {}
321
+ try { await helpers.teardownTestDb(tmpDir); } catch (_e) {}
322
+ _psql(FRAMEWORK_TABLES.map(function (t) {
323
+ return "DROP TABLE IF EXISTS " + t + " CASCADE;";
324
+ }).join("\n"));
325
+ }
326
+
327
+ // Replay every recorded finding through the hard `check` so the file
328
+ // FAILS (and the runner reports it) when any contract is unmet. All
329
+ // findings have already been printed above.
330
+ var failures = _findings.filter(function (f) { return !f.ok; });
331
+ console.log("");
332
+ console.log("[data-layer-pg] " + (_findings.length - failures.length) + "/" +
333
+ _findings.length + " checks ok; " + failures.length + " failing");
334
+ for (var i = 0; i < _findings.length; i++) {
335
+ check(_findings[i].label, _findings[i].ok);
336
+ }
337
+ }
338
+
339
+ // Run one primitive's section; a thrown driver error becomes a single
340
+ // FAILED finding so an unexpected error in one section doesn't hide the
341
+ // others' results.
342
+ async function _section(label, fn) {
343
+ try {
344
+ await fn();
345
+ } catch (e) {
346
+ softCheck(label + "(pg): section completed without an unexpected error " +
347
+ "— DETAIL: " + (((e && e.message) || String(e)).split(/\r?\n/)[0]), false);
348
+ }
349
+ }
350
+
351
+ // ======================================================================
352
+ // b.session full lifecycle on real Postgres (sealed at rest).
353
+ // ======================================================================
354
+ async function _testSession() {
355
+ // create -> returns a sealed-cookie token; the DB row keys on sha3(sid),
356
+ // userId+data sealed, userIdHash derived.
357
+ var created = await b.session.create({
358
+ userId: "user-42",
359
+ data: { roles: ["admin"], theme: "dark" },
360
+ ttlMs: b.constants.TIME.hours(8),
361
+ });
362
+ softCheck("session(pg): create returns a sealed token + expiry",
363
+ created && typeof created.token === "string" &&
364
+ created.token.indexOf("vault:") === 0 && typeof created.expiresAt === "number");
365
+
366
+ // The row physically landed on Postgres; userId is NOT plaintext.
367
+ var rawRows = _psql('SELECT "userId", "userIdHash" FROM _blamejs_sessions;');
368
+ softCheck("session(pg): a session row physically landed on Postgres",
369
+ rawRows.trim().length > 0);
370
+ softCheck("session(pg): userId is sealed at rest (NOT the plaintext 'user-42')",
371
+ rawRows.indexOf("user-42") === -1);
372
+
373
+ // verify -> unseal round-trips userId + data through Postgres.
374
+ var info = await b.session.verify(created.token);
375
+ softCheck("session(pg): verify unseals userId from the Postgres row",
376
+ info && info.userId === "user-42");
377
+ softCheck("session(pg): verify unseals the data payload",
378
+ info && info.data && info.data.roles && info.data.roles[0] === "admin" &&
379
+ info.data.theme === "dark");
380
+ softCheck("session(pg): verify coerces createdAt/expiresAt to JS numbers " +
381
+ "(BIGINT-as-string would break the timeout math)",
382
+ typeof info.createdAt === "number" && typeof info.expiresAt === "number" &&
383
+ info.expiresAt > info.createdAt);
384
+
385
+ // count -> the live session is counted (BIGINT count coerced to number).
386
+ var liveCount = await b.session.count();
387
+ softCheck("session(pg): count() returns the one live session as a JS number",
388
+ typeof liveCount === "number" && liveCount === 1);
389
+
390
+ // touch with extendBy -> bumps lastActivity + expiresAt; affectedRows>0.
391
+ var touched = await b.session.touch(created.token, { extendBy: b.constants.TIME.hours(12) });
392
+ softCheck("session(pg): touch() updated the live row (returned true)", touched === true);
393
+ var afterTouch = await b.session.verify(created.token);
394
+ softCheck("session(pg): touch extended expiresAt past the original",
395
+ afterTouch && afterTouch.expiresAt >= created.expiresAt);
396
+
397
+ // rotate -> new sid swapped atomically; old token no longer verifies.
398
+ var rotated = await b.session.rotate(created.token, { reason: "mfa" });
399
+ softCheck("session(pg): rotate returns a fresh sealed token",
400
+ rotated && typeof rotated.token === "string" && rotated.token !== created.token);
401
+ softCheck("session(pg): the OLD token no longer verifies after rotate",
402
+ (await b.session.verify(created.token)) === null);
403
+ var rotatedInfo = await b.session.verify(rotated.token);
404
+ softCheck("session(pg): the NEW token verifies with the same userId",
405
+ rotatedInfo && rotatedInfo.userId === "user-42");
406
+
407
+ // updateData -> writes the sealed data column without rotating the sid.
408
+ // The SELECT-then-UPDATE both dialect-thread through _sessionSqlOpts(); the
409
+ // data column round-trips through the sealed Postgres TEXT column.
410
+ var updated = await b.session.updateData(rotated.token, { roles: ["admin"], step: "mfa-done" });
411
+ softCheck("session(pg): updateData wrote the sealed data column (returned true)",
412
+ updated === true);
413
+ var afterUpdate = await b.session.verify(rotated.token);
414
+ softCheck("session(pg): updateData payload round-trips through the sealed Postgres column",
415
+ afterUpdate && afterUpdate.data && afterUpdate.data.step === "mfa-done");
416
+
417
+ // destroyAllForUser -> deletes via the derived userIdHash; count drops.
418
+ var revoked = await b.session.destroyAllForUser("user-42");
419
+ softCheck("session(pg): destroyAllForUser deleted the session via userIdHash",
420
+ revoked === 1);
421
+ softCheck("session(pg): the session no longer verifies after revoke-all",
422
+ (await b.session.verify(rotated.token)) === null);
423
+ softCheck("session(pg): count() is 0 after revoke-all", (await b.session.count()) === 0);
424
+
425
+ // destroy single + purgeExpired side-effects.
426
+ var s2 = await b.session.create({ userId: "user-99", ttlMs: b.constants.TIME.hours(1) });
427
+ softCheck("session(pg): destroy(token) returns true for a live session",
428
+ (await b.session.destroy(s2.token)) === true);
429
+ softCheck("session(pg): destroy is idempotent (second destroy returns false)",
430
+ (await b.session.destroy(s2.token)) === false);
431
+
432
+ // Insert an already-expired session directly so purgeExpired has work.
433
+ var expiredSidRow = await b.session.create({ userId: "user-exp", ttlMs: b.constants.TIME.hours(1) });
434
+ void expiredSidRow;
435
+ _psql('UPDATE _blamejs_sessions SET "expiresAt" = 1 WHERE "expiresAt" > 1;');
436
+ var purged = await b.session.purgeExpired();
437
+ softCheck("session(pg): purgeExpired removed the expired row(s) (>=1)", purged >= 1);
438
+ softCheck("session(pg): count() is 0 after purge", (await b.session.count()) === 0);
439
+ }
440
+
441
+ // ======================================================================
442
+ // b.cache cluster backend on real Postgres.
443
+ // ======================================================================
444
+ async function _testCacheCluster() {
445
+ var cache = b.cache.create({ backend: "cluster", namespace: "pgns", ttlMs: b.constants.TIME.minutes(5) });
446
+
447
+ await cache.set("k1", { hello: "world", n: 42 });
448
+ var got = await cache.get("k1");
449
+ softCheck("cache(pg): set + get JSON round-trips on real Postgres",
450
+ got && got.hello === "world" && got.n === 42);
451
+
452
+ var rowDirect = _psql("SELECT \"valueJson\" FROM _blamejs_cache WHERE \"cacheKey\" = 'pgns:k1';");
453
+ softCheck("cache(pg): row physically present under the composite key",
454
+ /"hello"/.test(rowDirect));
455
+
456
+ softCheck("cache(pg): has() returns true for a live key", (await cache.has("k1")) === true);
457
+ softCheck("cache(pg): del() removes the key", (await cache.del("k1")) === true);
458
+ softCheck("cache(pg): get() after del is undefined", (await cache.get("k1")) === undefined);
459
+
460
+ // tags + invalidateTag (whereLike prefix scoping).
461
+ await cache.set("a", "1", { tags: ["grp-x"] });
462
+ await cache.set("bk", "2", { tags: ["grp-x", "grp-y"] });
463
+ await cache.set("ck", "3", { tags: ["grp-y"] });
464
+ var tagsA = await cache.getTags("a");
465
+ softCheck("cache(pg): getTags returns the tags written for a key",
466
+ Array.isArray(tagsA) && tagsA.indexOf("grp-x") !== -1);
467
+
468
+ var purged = await cache.invalidateTag("grp-x");
469
+ softCheck("cache(pg): invalidateTag purged the grp-x keys (>=2)", purged >= 2);
470
+ softCheck("cache(pg): invalidateTag dropped a + bk",
471
+ (await cache.get("a")) === undefined && (await cache.get("bk")) === undefined);
472
+ softCheck("cache(pg): invalidateTag preserved grp-y-only key ck",
473
+ (await cache.get("ck")) === "3");
474
+
475
+ // atomic update (CAS) increment.
476
+ await cache.update("counter", function (n) { return { value: (n || 0) + 1 }; });
477
+ await cache.update("counter", function (n) { return { value: (n || 0) + 1 }; });
478
+ softCheck("cache(pg): atomic update() increments through transaction+CAS",
479
+ (await cache.get("counter")) === 2);
480
+
481
+ // size() counts only live namespaced rows.
482
+ var sz = await cache.size();
483
+ softCheck("cache(pg): size() counts live namespaced rows as a number",
484
+ typeof sz === "number" && sz >= 1);
485
+
486
+ var cleared = await cache.clear();
487
+ softCheck("cache(pg): clear() wiped the namespace (>=1)", cleared >= 1);
488
+ softCheck("cache(pg): get after clear is undefined", (await cache.get("ck")) === undefined);
489
+
490
+ await cache.close();
491
+ }
492
+
493
+ // ======================================================================
494
+ // b.nonceStore cluster backend on real Postgres.
495
+ // ======================================================================
496
+ async function _testNonceCluster() {
497
+ var store = b.nonceStore.create({ backend: "cluster" });
498
+ var future = Date.now() + b.constants.TIME.minutes(10);
499
+
500
+ softCheck("nonce(pg): first checkAndInsert returns true (unseen)",
501
+ (await store.checkAndInsert("nonce-aaa", future)) === true);
502
+ var n1 = _psql("SELECT count(*) AS n FROM _blamejs_api_encrypt_nonces WHERE \"nonceHash\" = 'nonce-aaa';");
503
+ softCheck("nonce(pg): the nonce row physically landed", /\b1\b/.test(n1.trim()));
504
+
505
+ softCheck("nonce(pg): replay of the same nonce returns false (ON CONFLICT DO NOTHING)",
506
+ (await store.checkAndInsert("nonce-aaa", future)) === false);
507
+ softCheck("nonce(pg): a distinct nonce is accepted",
508
+ (await store.checkAndInsert("nonce-bbb", future)) === true);
509
+
510
+ await store.checkAndInsert("nonce-expired", Date.now() - 1000);
511
+ var purged = await store.purgeExpired();
512
+ softCheck("nonce(pg): purgeExpired removed the expired nonce (>=1)", purged >= 1);
513
+ softCheck("nonce(pg): a live nonce still rejects replay after purge",
514
+ (await store.checkAndInsert("nonce-aaa", future)) === false);
515
+
516
+ store.close();
517
+ }
518
+
519
+ // ======================================================================
520
+ // b.middleware.rateLimit cluster backend on real Postgres.
521
+ // take() = ON CONFLICT increment with a CASE conflict action +
522
+ // RETURNING; the returned BIGINT count must coerce to a JS number so
523
+ // count<=limit is a numeric comparison (a string "10" <= 3 would be a
524
+ // silent always-allow).
525
+ // ======================================================================
526
+ async function _testRateLimitCluster() {
527
+ var backend = rateLimitModule._clusterBackend({
528
+ backend: "cluster", limit: 3, windowMs: b.constants.TIME.minutes(1),
529
+ });
530
+
531
+ var v1 = await backend.take("ratekey-1", 1);
532
+ softCheck("rate-limit(pg): first take() is allowed against real Postgres",
533
+ v1 && v1.allowed === true);
534
+ softCheck("rate-limit(pg): the take() verdict count math is numeric " +
535
+ "(remaining is a finite number, not NaN from a string compare)",
536
+ typeof v1.remaining === "number" && isFinite(v1.remaining) && v1.remaining === 2);
537
+
538
+ var rowAfter1 = _psql("SELECT \"count\" FROM _blamejs_rate_limit_counters WHERE \"key\" = 'ratekey-1';");
539
+ softCheck("rate-limit(pg): counter row landed with count=1", /\b1\b/.test(rowAfter1.trim()));
540
+
541
+ var v2 = await backend.take("ratekey-1", 1);
542
+ var v3 = await backend.take("ratekey-1", 1);
543
+ var v4 = await backend.take("ratekey-1", 1);
544
+ softCheck("rate-limit(pg): 2nd + 3rd allowed, 4th over the limit refused",
545
+ v2.allowed === true && v3.allowed === true && v4.allowed === false);
546
+ softCheck("rate-limit(pg): the over-limit verdict carries a positive retryAfter",
547
+ typeof v4.retryAfter === "number" && v4.retryAfter > 0);
548
+ var rowAfter4 = _psql("SELECT \"count\" FROM _blamejs_rate_limit_counters WHERE \"key\" = 'ratekey-1';");
549
+ softCheck("rate-limit(pg): counter incremented monotonically to 4",
550
+ /\b4\b/.test(rowAfter4.trim()));
551
+
552
+ // A window advance resets the count (the CASE conflict action's
553
+ // window-rollover branch). Force a stale window then take() again.
554
+ _psql("UPDATE _blamejs_rate_limit_counters SET \"windowStart\" = 0 WHERE \"key\" = 'ratekey-1';");
555
+ var vReset = await backend.take("ratekey-1", 1);
556
+ softCheck("rate-limit(pg): a fresh window resets the count (CASE rollover) — allowed again",
557
+ vReset.allowed === true);
558
+ var rowAfterReset = _psql("SELECT \"count\" FROM _blamejs_rate_limit_counters WHERE \"key\" = 'ratekey-1';");
559
+ softCheck("rate-limit(pg): count reset to 1 on window advance",
560
+ /\b1\b/.test(rowAfterReset.trim()));
561
+
562
+ // A distinct key is tracked independently.
563
+ var other = await backend.take("ratekey-2", 1);
564
+ softCheck("rate-limit(pg): a distinct key is counted independently",
565
+ other.allowed === true && other.remaining === 2);
566
+
567
+ if (typeof backend.close === "function") backend.close();
568
+ }
569
+
570
+ module.exports = { run: run };
571
+
572
+ if (require.main === module) {
573
+ run().then(
574
+ function () { console.log("OK — " + helpers.getChecks() + " checks passed"); process.exit(0); },
575
+ function (e) { console.error("FAIL:", e.stack || e); process.exit(1); }
576
+ );
577
+ }