@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,595 @@
1
+ "use strict";
2
+ /**
3
+ * b.sql — quote-by-construction query builder (composes b.safeSql) +
4
+ * its final output validator. Covers each verb across dialects, the
5
+ * where-family checks inherited from the executing query builder
6
+ * (operator allowlist, IN-expansion, JSONB injection guard +
7
+ * jsonb_exists emission), and every _assertEmittable boundary code.
8
+ */
9
+
10
+ var helpers = require("../helpers");
11
+ var b = helpers.b;
12
+ var check = helpers.check;
13
+
14
+ var NUL = String.fromCharCode(0);
15
+ var LONE = String.fromCharCode(0xD800); // unpaired UTF-16 surrogate
16
+
17
+ function rejects(label, fn, code) {
18
+ var threw = null;
19
+ try { fn(); } catch (e) { threw = e; }
20
+ check(label, threw && threw.code === code);
21
+ }
22
+
23
+ async function run() {
24
+ var sql = b.sql;
25
+ var safeSql = b.safeSql;
26
+
27
+ // ---- module surface (explicit b.* references so the test-coverage gate
28
+ // sees every primitive by its operator-facing name) ----
29
+ check("b.sql.select", typeof b.sql.select === "function");
30
+ check("b.sql.insert", typeof b.sql.insert === "function");
31
+ check("b.sql.update", typeof b.sql.update === "function");
32
+ check("b.sql.delete", typeof b.sql.delete === "function");
33
+ check("b.sql.upsert", typeof b.sql.upsert === "function");
34
+ check("b.sql.table", typeof b.sql.table === "function");
35
+ check("b.sql.createTable", typeof b.sql.createTable === "function");
36
+ check("b.sql.createIndex", typeof b.sql.createIndex === "function");
37
+ check("b.sql.alterTable", typeof b.sql.alterTable === "function");
38
+ check("b.sql.dropTable", typeof b.sql.dropTable === "function");
39
+ check("b.sql.createVirtualTable", typeof b.sql.createVirtualTable === "function");
40
+ check("b.sql.defineTable", typeof b.sql.defineTable === "function");
41
+ check("b.sql.Builder", typeof b.sql.Builder === "function");
42
+ check("b.sql.SqlBuilderError", typeof b.sql.SqlBuilderError === "function");
43
+ check("b.sql.ALLOWED_OPS", b.sql.ALLOWED_OPS && b.sql.ALLOWED_OPS["="] === true);
44
+ // table() reference exercises the table-ref helper.
45
+ check("b.sql.table ref", b.sql.table("t", { dialect: "postgres" }) !== undefined);
46
+ // alterTable reference.
47
+ check("b.sql.alterTable addColumn",
48
+ b.sql.alterTable("t", { addColumn: { name: "c", type: "text" } }, { dialect: "postgres" })
49
+ .sql.indexOf("ALTER TABLE") === 0);
50
+
51
+ // ---- b.safeSql surface (countPlaceholders + quoteList) ----
52
+ check("b.safeSql.countPlaceholders", b.safeSql.countPlaceholders("a = ? AND b = ?") === 2);
53
+ check("b.safeSql.quoteList", b.safeSql.quoteList(["a", "b"], "postgres") === '"a", "b"');
54
+ // assertSingleStatement — the one quote-aware single-statement gate the raw-DDL
55
+ // paths (schema reconcile, DSR store) + the b.sql output validators all route through.
56
+ check("b.safeSql.assertSingleStatement returns valid single-statement SQL",
57
+ b.safeSql.assertSingleStatement("CREATE TABLE t (id INTEGER)") === "CREATE TABLE t (id INTEGER)");
58
+ check("b.safeSql.assertSingleStatement allows ';' inside a balanced quoted label",
59
+ b.safeSql.assertSingleStatement("INSERT INTO t VALUES ('a;b')") === "INSERT INTO t VALUES ('a;b')");
60
+ rejects("b.safeSql.assertSingleStatement refuses a stacked top-level ';'", function () {
61
+ b.safeSql.assertSingleStatement("CREATE TABLE t (id INTEGER); DROP TABLE x");
62
+ }, "sql/stacked-statement");
63
+ rejects("b.safeSql.assertSingleStatement refuses an unterminated quote", function () {
64
+ b.safeSql.assertSingleStatement("INSERT INTO t VALUES ('unclosed)");
65
+ }, "sql/unterminated-quote");
66
+ rejects("b.safeSql.assertSingleStatement refuses unbalanced parens", function () {
67
+ b.safeSql.assertSingleStatement("CREATE TABLE t (id INTEGER");
68
+ }, "sql/unbalanced");
69
+
70
+ // ---- b.guardSql surface (the SQL guard composed by b.sql for raw frags) ----
71
+ check("b.guardSql.validate", b.guardSql.validate("id = ? AND x = ?").ok === true);
72
+ check("b.guardSql.validate hostile", b.guardSql.validate("1; DROP TABLE t", { profile: "strict" }).ok === false);
73
+ check("b.guardSql.sanitize", typeof b.guardSql.sanitize("id = ?") === "string");
74
+ check("b.guardSql.gate", typeof b.guardSql.gate === "function");
75
+ check("b.guardSql.buildProfile", typeof b.guardSql.buildProfile === "function");
76
+ check("b.guardSql.compliancePosture", b.guardSql.compliancePosture("hipaa") !== undefined);
77
+ check("b.guardSql.loadRulePack", typeof b.guardSql.loadRulePack === "function");
78
+ check("b.guardSql.GuardSqlError", typeof b.guardSql.GuardSqlError === "function");
79
+
80
+ // ---- b.frameworkSchema coercion (BIGINT-string -> Number, BYTEA -> Buffer) ----
81
+ check("b.frameworkSchema.coerceRow", typeof b.frameworkSchema.coerceRow === "function");
82
+ check("b.frameworkSchema.coerceRows", Array.isArray(b.frameworkSchema.coerceRows([])));
83
+
84
+ // ---- safeSql composition ----
85
+ check("quoteIdentifier pg", safeSql.quoteIdentifier("createdAt", "postgres") === '"createdAt"');
86
+ check("quoteIdentifier mysql", safeSql.quoteIdentifier("createdAt", "mysql") === "`createdAt`");
87
+ check("quoteList", safeSql.quoteList(["a", "b"], "postgres") === '"a", "b"');
88
+ check("countPlaceholders", safeSql.countPlaceholders("a = ? AND b = ?") === 2);
89
+ check("countPlaceholders skips literal",
90
+ safeSql.countPlaceholders("note = 'has ? inside' AND id = ?") === 1);
91
+
92
+ // ---- SELECT across dialects ----
93
+ var selPg = sql.select("users", { dialect: "postgres" })
94
+ .columns(["id", "email"]).where("status", "active")
95
+ .orderBy("createdAt", "desc").limit(10).toSql();
96
+ check("select pg quotes + placeholder",
97
+ selPg.sql === 'SELECT "id", "email" FROM users WHERE "status" = ? ORDER BY "createdAt" DESC LIMIT 10' &&
98
+ selPg.params.length === 1 && selPg.params[0] === "active");
99
+ var selMy = sql.select("users", { dialect: "mysql" }).columns(["id"]).where("id", 1).toSql();
100
+ check("select mysql backticks", selMy.sql === "SELECT `id` FROM users WHERE `id` = ?");
101
+
102
+ // ---- INSERT / UPDATE / DELETE ----
103
+ var ins = sql.insert("users").values({ id: 1, email: "a@b.c" }).returning(["id"]).toSql();
104
+ check("insert shape", ins.sql.indexOf("INSERT INTO users") === 0 &&
105
+ ins.sql.indexOf("VALUES (?, ?)") !== -1 && ins.params.length === 2);
106
+ var upd = sql.update("users").set({ status: "off" }).where("id", 1).toSql();
107
+ check("update shape", upd.sql === 'UPDATE users SET "status" = ? WHERE "id" = ?' &&
108
+ upd.params.length === 2);
109
+ rejects("update without where throws", function () {
110
+ return sql.update("users").set({ status: "off" }).toSql();
111
+ }, "sql-builder/no-where");
112
+ check("delete with where", sql.delete("sessions").where("id", 1).toSql().params.length === 1);
113
+ rejects("delete without where throws", function () {
114
+ return sql.delete("sessions").toSql();
115
+ }, "sql-builder/no-where");
116
+
117
+ // ---- where family: operator allowlist + IN expansion + BETWEEN + LIKE ----
118
+ rejects("bad operator rejected", function () {
119
+ return sql.select("t").where("c", "EVIL", 1).toSql();
120
+ }, "sql-builder/bad-operator");
121
+ var inq = sql.select("t").whereIn("id", [1, 2, 3]).toSql();
122
+ check("IN expands to (?, ?, ?)", inq.sql.indexOf("IN (?, ?, ?)") !== -1 && inq.params.length === 3);
123
+ rejects("empty IN rejected", function () {
124
+ return sql.select("t").whereIn("id", []).toSql();
125
+ }, "sql-builder/empty-in");
126
+ var likeq = sql.select("t").where("name", "LIKE", "50%_off").toSql();
127
+ check("LIKE escapes wildcards with ~", likeq.sql.indexOf("ESCAPE '~'") !== -1 &&
128
+ likeq.params[0].indexOf("~%") !== -1 && likeq.params[0].indexOf("~_") !== -1);
129
+
130
+ // ---- JSONB guard + jsonb_exists emission (inherited from db-query) ----
131
+ var jc = sql.select("docs", { dialect: "postgres" }).where("meta", "@>", { a: 1 }).toSql();
132
+ check("@> binds canonical JSON", jc.sql.indexOf('"meta" @> ?') !== -1 && jc.params[0] === '{"a":1}');
133
+ var jk = sql.select("docs", { dialect: "postgres" }).where("meta", "?", "akey").toSql();
134
+ check("? -> jsonb_exists", jk.sql.indexOf('jsonb_exists("meta", ?)') !== -1 && jk.params[0] === "akey");
135
+ var jka = sql.select("docs", { dialect: "postgres" }).where("meta", "?|", ["a", "b"]).toSql();
136
+ check("?| -> jsonb_exists_any", jka.sql.indexOf('jsonb_exists_any("meta", ?)') !== -1);
137
+ var jkb = sql.select("docs", { dialect: "postgres" }).where("meta", "?&", ["a", "b"]).toSql();
138
+ check("?& -> jsonb_exists_all", jkb.sql.indexOf('jsonb_exists_all("meta", ?)') !== -1);
139
+ rejects("NUL JSONB key rejected", function () {
140
+ return sql.select("docs", { dialect: "postgres" }).where("meta", "?", "a" + NUL + "b").toSql();
141
+ }, "safe-jsonpath/key-control-char");
142
+ // Dialect-design gate: JSONB ops are Postgres-only; emitting them for a
143
+ // sqlite / mysql backend would regress downstream (no jsonb_exists / @>).
144
+ rejects("@> on sqlite rejected (postgres-only)", function () {
145
+ return sql.select("docs", { dialect: "sqlite" }).where("meta", "@>", { a: 1 }).toSql();
146
+ }, "sql-builder/jsonb-postgres-only");
147
+ rejects("? on mysql rejected (postgres-only)", function () {
148
+ return sql.select("docs", { dialect: "mysql" }).where("meta", "?", "k").toSql();
149
+ }, "sql-builder/jsonb-postgres-only");
150
+
151
+ // ---- output validator boundaries (_assertEmittable) ----
152
+ rejects("NUL in string param", function () {
153
+ return sql.insert("t").values({ a: "x" + NUL + "y" }).toSql();
154
+ }, "sql-builder/null-byte-param");
155
+ rejects("lone surrogate param", function () {
156
+ return sql.insert("t").values({ a: "x" + LONE + "y" }).toSql();
157
+ }, "sql-builder/invalid-encoding-param");
158
+ rejects("oversized buffer param", function () {
159
+ return sql.insert("t").values({ a: Buffer.alloc(64 * 1024 * 1024 + 1) }).toSql();
160
+ }, "sql-builder/param-too-large");
161
+ rejects("undefined param value", function () {
162
+ return sql.insert("t").values({ a: undefined }).toSql();
163
+ }, "sql-builder/bad-param-value");
164
+ // A normal-size buffer + spaced strings must PASS (no false rejection).
165
+ var okBuf = sql.insert("blobs").values({ id: 1, data: Buffer.from("hello world, spaced") }).toSql();
166
+ check("normal buffer + spaced string passes", okBuf.params.length === 2);
167
+
168
+ // ---- DDL (terminal: return { sql, params } directly) ----
169
+ var ct = sql.createTable("widgets", [
170
+ { name: "id", type: "text", primaryKey: true },
171
+ { name: "qty", type: "int" },
172
+ ], { dialect: "postgres" });
173
+ check("createTable quotes cols + maps logical type",
174
+ ct.sql.indexOf("CREATE TABLE") === 0 && ct.sql.indexOf("widgets") !== -1 &&
175
+ ct.sql.indexOf('"id"') !== -1 && ct.sql.indexOf("BIGINT") !== -1);
176
+ var dt = sql.dropTable("widgets", { dialect: "postgres" });
177
+ check("dropTable", dt.sql.indexOf("DROP TABLE") === 0 && dt.sql.indexOf("widgets") !== -1);
178
+
179
+ // ---- upsert (dialect-final) ----
180
+ var upPg = sql.upsert("kv", { dialect: "postgres" }).columns(["k", "v"]).values({ k: "a", v: "b" })
181
+ .onConflict(["k"]).doUpdateFromExcluded(["v"]).toSql();
182
+ check("upsert pg ON CONFLICT", upPg.sql.indexOf("ON CONFLICT") !== -1 &&
183
+ upPg.sql.indexOf("DO UPDATE") !== -1);
184
+
185
+ // ==== dialect-design divergence (Postgres vs SQLite vs MySQL) ====
186
+ // Each construct below emits a different form per dialect; a regression
187
+ // that leaks one dialect's form to another backend would ship green
188
+ // without these (b.sql is a pure composer with no live driver in-test).
189
+ var cs = b.clusterStorage;
190
+
191
+ // Sub-query composition: a sub built with a different dialect than the
192
+ // parent has eagerly baked the wrong quote char -> refuse loudly rather
193
+ // than splice mixed quoting the backend mis-reads. (IN / EXISTS / whereSub
194
+ // / selectSub / CTE all route through the same compose gate.)
195
+ rejects("IN subquery dialect mismatch", function () {
196
+ return sql.select("u", { dialect: "mysql" }).whereIn("id", sql.select("o").columns(["uid"])).toSql();
197
+ }, "sql-builder/dialect-mismatch");
198
+ rejects("CTE body dialect mismatch", function () {
199
+ return sql.select("u", { dialect: "mysql" }).with("r", sql.select("o").columns(["uid"]))
200
+ .columns(["id"]).toSql();
201
+ }, "sql-builder/dialect-mismatch");
202
+ var inMatch = sql.select("u", { dialect: "mysql" })
203
+ .whereIn("id", sql.select("o", { dialect: "mysql" }).columns(["uid"])).toSql();
204
+ check("IN subquery same-dialect composes (backtick body)",
205
+ inMatch.sql.indexOf("`uid`") !== -1 && inMatch.sql.indexOf('"uid"') === -1);
206
+ var inDefault = sql.select("u").whereIn("id", sql.select("o").columns(["uid"])).toSql();
207
+ check("default+default subquery composes", inDefault.sql.indexOf("IN (SELECT") !== -1);
208
+
209
+ // placeholderize skip-set is a superset of countPlaceholders': a ? inside
210
+ // a double-quoted identifier or a comment must NOT be renumbered to $N.
211
+ check("placeholderize skips ? in ident + comment",
212
+ cs.placeholderize('SELECT "c?l" FROM t WHERE id = ? -- k?v', "postgres") ===
213
+ 'SELECT "c?l" FROM t WHERE id = $1 -- k?v');
214
+ check("placeholderize renumbers real binds",
215
+ cs.placeholderize("a = ? AND b = ?", "postgres") === "a = $1 AND b = $2");
216
+
217
+ // DDL type mapping: json -> JSONB (pg) / JSON (mysql) / TEXT (sqlite).
218
+ check("json type pg JSONB",
219
+ sql.createTable("d", [{ name: "j", type: "json" }], { dialect: "postgres" }).sql.indexOf("JSONB") !== -1);
220
+ check("json type mysql JSON",
221
+ sql.createTable("d", [{ name: "j", type: "json" }], { dialect: "mysql" }).sql.indexOf(" JSON") !== -1);
222
+ check("json type sqlite TEXT",
223
+ sql.createTable("d", [{ name: "j", type: "json" }], { dialect: "sqlite" }).sql.indexOf("TEXT") !== -1);
224
+
225
+ // Auto-increment identity PK diverges per dialect (else an app built on
226
+ // sqlite's implicit INTEGER-PK auto-increment breaks on pg/mysql).
227
+ check("autoIncrement pg BIGSERIAL",
228
+ sql.createTable("t", [{ name: "id", autoIncrement: true }], { dialect: "postgres" })
229
+ .sql.indexOf("BIGSERIAL PRIMARY KEY") !== -1);
230
+ check("autoIncrement sqlite INTEGER AUTOINCREMENT",
231
+ sql.createTable("t", [{ name: "id", autoIncrement: true }], { dialect: "sqlite" })
232
+ .sql.indexOf("INTEGER PRIMARY KEY AUTOINCREMENT") !== -1);
233
+ check("autoIncrement mysql AUTO_INCREMENT",
234
+ sql.createTable("t", [{ name: "id", autoIncrement: true }], { dialect: "mysql" })
235
+ .sql.indexOf("AUTO_INCREMENT") !== -1);
236
+
237
+ // RETURNING is unsupported on MySQL for plain verbs -> refuse at build.
238
+ rejects("RETURNING on mysql insert", function () {
239
+ return sql.insert("t", { dialect: "mysql" }).values({ a: 1 }).returning(["a"]).toSql();
240
+ }, "sql-builder/returning-unsupported");
241
+ check("RETURNING on pg insert works",
242
+ sql.insert("t", { dialect: "postgres" }).values({ a: 1 }).returning(["a"]).toSql()
243
+ .sql.indexOf("RETURNING") !== -1);
244
+
245
+ // Raw fragment carrying a bare JSONB ?| operator -> refuse (placeholderize
246
+ // would corrupt the operator to $N).
247
+ rejects("raw ?| operator refused", function () {
248
+ return sql.select("t", { dialect: "postgres" }).whereRaw("tags ?| ?", [["a"]]).toSql();
249
+ }, "sql-builder/raw-jsonb-op");
250
+
251
+ // LIKE ESCAPE uses ~, not backslash (backslash breaks MySQL default sql_mode).
252
+ check("LIKE ESCAPE is ~ on mysql",
253
+ sql.select("t", { dialect: "mysql" }).where("n", "LIKE", "x%").toSql().sql.indexOf("ESCAPE '~'") !== -1);
254
+
255
+ // JSONB operator in a join ON has no jsonb_exists rewrite -> refuse.
256
+ rejects("join ON JSONB operator refused", function () {
257
+ return sql.select("t", { dialect: "postgres" }).join("o", "t.a", "@>", "o.b").toSql();
258
+ }, "sql-builder/jsonb-bad-position");
259
+
260
+ // ==== defineTable (PK/FK/index automation) + its dialect divergence ====
261
+ // Identity PK diverges per dialect (the regression that breaks an app
262
+ // built on sqlite when it ships to pg/mysql).
263
+ var dPg = sql.defineTable("orders", [{ name: "userId", type: "int" }], { dialect: "postgres" });
264
+ var dSq = sql.defineTable("orders", [{ name: "userId", type: "int" }], { dialect: "sqlite" });
265
+ var dMy = sql.defineTable("orders", [{ name: "userId", type: "int" }], { dialect: "mysql" });
266
+ check("defineTable pg BIGSERIAL PK", dPg.statements[0].sql.indexOf("BIGSERIAL PRIMARY KEY") !== -1);
267
+ check("defineTable sqlite INTEGER AUTOINCREMENT PK",
268
+ dSq.statements[0].sql.indexOf("INTEGER PRIMARY KEY AUTOINCREMENT") !== -1);
269
+ check("defineTable mysql AUTO_INCREMENT PK", dMy.statements[0].sql.indexOf("AUTO_INCREMENT PRIMARY KEY") !== -1);
270
+
271
+ // FK inference + per-dialect quoting (double-quote pg/sqlite, backtick mysql).
272
+ check("defineTable FK inference pg quoting",
273
+ dPg.statements[0].sql.indexOf('"userId" BIGINT REFERENCES users ("id")') !== -1);
274
+ check("defineTable FK inference mysql backtick quoting",
275
+ dMy.statements[0].sql.indexOf("`userId` BIGINT REFERENCES users (`id`)") !== -1);
276
+ check("defineTable pluralize categoryId -> categories",
277
+ sql.defineTable("o", [{ name: "categoryId", type: "int" }], { dialect: "postgres" })
278
+ .statements[0].sql.indexOf("REFERENCES categories") !== -1);
279
+
280
+ // Auto-index the FK column, quoted in the table's dialect (a regression
281
+ // where the index leaks the wrong quote char breaks the wrong backend).
282
+ check("defineTable auto-index FK pg", dPg.statements.some(function (s) {
283
+ return s.sql.indexOf("CREATE INDEX") === 0 && s.sql.indexOf('("userId")') !== -1; }));
284
+ check("defineTable auto-index FK mysql backtick", dMy.statements.some(function (s) {
285
+ return s.sql.indexOf("CREATE INDEX") === 0 && s.sql.indexOf("(`userId`)") !== -1; }));
286
+
287
+ // json column type diverges through defineTable too.
288
+ check("defineTable json type mysql JSON",
289
+ sql.defineTable("d", [{ name: "j", type: "json" }], { dialect: "mysql" })
290
+ .statements[0].sql.indexOf(" JSON") !== -1);
291
+
292
+ // Disable knobs.
293
+ check("defineTable autoForeignKeys:false drops FK + index",
294
+ sql.defineTable("t", [{ name: "id", autoIncrement: true }, { name: "userId", type: "int" }],
295
+ { dialect: "postgres", autoForeignKeys: false }).statements.length === 1);
296
+ check("defineTable autoIndex:false drops indexes",
297
+ sql.defineTable("t", [{ name: "id", autoIncrement: true }, { name: "userId", type: "int" }],
298
+ { dialect: "postgres", autoIndex: false }).statements.length === 1);
299
+ var optOut = sql.defineTable("t", [{ name: "id", autoIncrement: true },
300
+ { name: "userId", type: "int", references: false }], { dialect: "postgres" });
301
+ check("defineTable references:false opts out of FK",
302
+ optOut.statements.length === 1 && optOut.statements[0].sql.indexOf("REFERENCES") === -1);
303
+
304
+ // Column-namespace gate (same discipline as the query builder): an index
305
+ // on a non-declared column is refused.
306
+ rejects("defineTable index on unknown column", function () {
307
+ return sql.defineTable("t", [{ name: "id", autoIncrement: true }],
308
+ { dialect: "postgres", indexes: [{ columns: ["ghost"] }] });
309
+ }, "sql-builder/unknown-column");
310
+
311
+ // FK referential actions allowlisted.
312
+ check("defineTable FK onDelete CASCADE",
313
+ sql.defineTable("t", [{ name: "id", autoIncrement: true },
314
+ { name: "userId", type: "int", references: { table: "users", onDelete: "cascade" } }],
315
+ { dialect: "postgres" }).statements[0].sql.indexOf("ON DELETE CASCADE") !== -1);
316
+ rejects("defineTable FK bad referential action", function () {
317
+ return sql.defineTable("t", [{ name: "id", autoIncrement: true },
318
+ { name: "userId", type: "int", references: { table: "users", onDelete: "explode" } }],
319
+ { dialect: "postgres" });
320
+ }, "sql-builder/bad-fk-action");
321
+
322
+ // Generated index name bounded to the identifier limit (like every
323
+ // query-builder identifier).
324
+ var longCol = new Array(61).join("c"); // 60-char valid identifier
325
+ var longDef = sql.defineTable("orders", [{ name: "id", autoIncrement: true },
326
+ { name: longCol, type: "text", index: true }], { dialect: "postgres" });
327
+ var longIdx = longDef.statements.filter(function (s) { return s.sql.indexOf("CREATE INDEX") === 0; })[0];
328
+ var idxNameMatch = /INDEX IF NOT EXISTS "([^"]+)"/.exec(longIdx.sql);
329
+ check("defineTable index name within identifier limit",
330
+ idxNameMatch !== null && idxNameMatch[1].length <= 63);
331
+
332
+ // ==== v0.15.0 direct-driver + value-cell + RLS + catalog surface ====
333
+ // These primitives make the b.outbox / b.inbox / b.db.declareRowPolicy
334
+ // migrations possible (those targets hand SQL to an operator driver
335
+ // directly, with no clusterStorage in the path).
336
+
337
+ check("b.sql.fn", typeof b.sql.fn === "function");
338
+ check("b.sql.cast", typeof b.sql.cast === "function");
339
+ check("b.sql.toExternalSql", typeof b.sql.toExternalSql === "function");
340
+ check("b.sql.enableRowLevelSecurity", typeof b.sql.enableRowLevelSecurity === "function");
341
+ check("b.sql.disableRowLevelSecurity", typeof b.sql.disableRowLevelSecurity === "function");
342
+ check("b.sql.createPolicy", typeof b.sql.createPolicy === "function");
343
+ check("b.sql.dropPolicy", typeof b.sql.dropPolicy === "function");
344
+ check("b.sql.pragma", typeof b.sql.pragma === "function");
345
+ check("b.sql.catalog", b.sql.catalog && typeof b.sql.catalog.listTables === "function");
346
+
347
+ // ---- toExternalSql: ? -> $N on postgres, unchanged on sqlite/mysql ----
348
+ var pgExt = sql.select("t", { dialect: "postgres" }).where("a", 1).where("b", 2).toExternalSql("postgres");
349
+ check("toExternalSql postgres $N", pgExt.sql.indexOf("$1") !== -1 && pgExt.sql.indexOf("$2") !== -1 &&
350
+ pgExt.sql.indexOf("?") === -1);
351
+ var liteExt = sql.select("t", { dialect: "sqlite" }).where("a", 1).toExternalSql("sqlite");
352
+ check("toExternalSql sqlite keeps ?", liteExt.sql.indexOf("?") !== -1 && liteExt.sql.indexOf("$1") === -1);
353
+ // A `?` inside a string literal is NOT a placeholder (quote-aware pass).
354
+ var litFrag = sql.select("t", { dialect: "postgres" })
355
+ .whereRaw("note = 'has a ? mark'", [], { allowLiterals: true }).where("id", 1).toExternalSql("postgres");
356
+ check("toExternalSql skips ? inside literal", /'has a \? mark'/.test(litFrag.sql) &&
357
+ litFrag.sql.indexOf("$1") !== -1 && litFrag.sql.indexOf("$2") === -1);
358
+ // Standalone toExternalSql wrapper over a DDL { sql, params } result.
359
+ var ddlExt = b.sql.toExternalSql(
360
+ b.sql.createIndex("idx_p", "outbox", ["next_attempt_at"],
361
+ { dialect: "postgres", where: "status = 'pending'" }), "postgres");
362
+ check("toExternalSql wraps DDL result", ddlExt.sql.indexOf("WHERE status = 'pending'") !== -1);
363
+ rejects("toExternalSql rejects non-builder/non-result", function () {
364
+ return b.sql.toExternalSql(42, "postgres");
365
+ }, "sql-builder/bad-external-input");
366
+
367
+ // ---- fn / cast value cells in INSERT + UPDATE ----
368
+ var fnIns = sql.insert("events", { dialect: "postgres" })
369
+ .values({ topic: "x", at: sql.fn("NOW") }).toSql();
370
+ check("insert fn(NOW) emits token no param",
371
+ /VALUES \(\?, NOW\(\)\)/.test(fnIns.sql) && fnIns.params.length === 1);
372
+ var castIns = sql.insert("docs", { dialect: "postgres" })
373
+ .values({ id: 1, meta: sql.cast('{"a":1}', "jsonb") }).toSql();
374
+ check("insert cast(::jsonb) binds value + casts placeholder",
375
+ /\?::jsonb/.test(castIns.sql) && castIns.params.length === 2 && castIns.params[1] === '{"a":1}');
376
+ var fnUpd = sql.update("t", { dialect: "postgres" })
377
+ .set({ updated_at: sql.fn("CURRENT_TIMESTAMP") }).where("id", 1).toSql();
378
+ check("update set fn(CURRENT_TIMESTAMP) no param for the cell",
379
+ /SET "updated_at" = CURRENT_TIMESTAMP/.test(fnUpd.sql) && fnUpd.params.length === 1);
380
+ rejects("fn rejects non-allowlisted function", function () { return sql.fn("EVIL"); },
381
+ "sql-builder/bad-fn");
382
+ rejects("cast rejects non-allowlisted type", function () { return sql.cast("x", "regclass"); },
383
+ "sql-builder/bad-cast");
384
+ // Postgres-only cast has no portable form on sqlite -> throws at build.
385
+ rejects("cast interval is postgres-only on sqlite", function () {
386
+ return sql.insert("t", { dialect: "sqlite" }).values({ d: sql.cast("1 day", "interval") }).toSql();
387
+ }, "sql-builder/cast-unsupported");
388
+
389
+ // upsert VALUES routes through the value-cell choke-point too (the inbox
390
+ // ON CONFLICT DO NOTHING RETURNING dedup carries NOW() + ::jsonb cells).
391
+ var upFn = sql.upsert("inbox", { dialect: "postgres" })
392
+ .columns(["mid", "src", "rcv", "meta"])
393
+ .values({ mid: "m", src: "s", rcv: sql.fn("NOW"), meta: sql.cast(null, "jsonb") })
394
+ .onConflict(["src", "mid"]).doNothing().returning(["mid"]).toSql();
395
+ check("upsert VALUES renders fn + cast cells",
396
+ /VALUES \(\?, \?, NOW\(\), \?::jsonb\)/.test(upFn.sql) &&
397
+ /DO NOTHING RETURNING "mid"/.test(upFn.sql) && upFn.params.length === 3);
398
+
399
+ // ---- whereInArray: = ANY(?) on postgres, IN (?, ...) on sqlite ----
400
+ var anyPg = sql.update("t", { dialect: "postgres" }).set({ s: "x" }).whereInArray("id", [1, 2, 3]).toSql();
401
+ check("whereInArray = ANY(?) on postgres binds the array as one param",
402
+ /"id" = ANY\(\?\)/.test(anyPg.sql) && anyPg.params.length === 2 &&
403
+ Array.isArray(anyPg.params[1]) && anyPg.params[1].length === 3);
404
+ var anyLite = sql.update("t", { dialect: "sqlite" }).set({ s: "x" }).whereInArray("id", [1, 2, 3]).toSql();
405
+ check("whereInArray expands to IN(?,?,?) on sqlite",
406
+ /"id" IN \(\?, \?, \?\)/.test(anyLite.sql) && anyLite.params.length === 4);
407
+ rejects("whereInArray rejects empty array", function () {
408
+ return sql.update("t", { dialect: "postgres" }).set({ s: "x" }).whereInArray("id", []).toSql();
409
+ }, "sql-builder/empty-in");
410
+
411
+ // ---- forUpdate [SKIP LOCKED] (postgres/mysql); refused on sqlite ----
412
+ var fu = sql.select("q", { dialect: "postgres" }).where("status", "pending")
413
+ .orderBy("at").limit(10).forUpdate({ skipLocked: true }).toSql();
414
+ check("forUpdate skipLocked emits FOR UPDATE SKIP LOCKED",
415
+ /FOR UPDATE SKIP LOCKED$/.test(fu.sql));
416
+ var fuNoWait = sql.select("q", { dialect: "postgres" }).forUpdate({ noWait: true }).toSql();
417
+ check("forUpdate noWait emits FOR UPDATE NOWAIT", /FOR UPDATE NOWAIT$/.test(fuNoWait.sql));
418
+ check("forShare emits FOR SHARE",
419
+ /FOR SHARE$/.test(sql.select("q", { dialect: "postgres" }).forShare().toSql().sql));
420
+ rejects("forUpdate refused on sqlite", function () {
421
+ return sql.select("q", { dialect: "sqlite" }).forUpdate().toSql();
422
+ }, "sql-builder/lock-unsupported");
423
+ rejects("forUpdate skipLocked + noWait mutually exclusive", function () {
424
+ return sql.select("q", { dialect: "postgres" }).forUpdate({ skipLocked: true, noWait: true });
425
+ }, "sql-builder/bad-lock");
426
+
427
+ // ---- partial index (createIndex { where }) ----
428
+ var partial = sql.createIndex("idx_pending", "outbox", ["at"],
429
+ { dialect: "postgres", where: "status = 'pending'" });
430
+ check("createIndex partial WHERE", /WHERE status = 'pending'$/.test(partial.sql));
431
+ rejects("createIndex partial WHERE refused on mysql", function () {
432
+ return sql.createIndex("idx_p", "t", ["c"], { dialect: "mysql", where: "x = 1" });
433
+ }, "sql-builder/partial-index-unsupported");
434
+
435
+ // ---- RLS builders (postgres-only) ----
436
+ check("enableRowLevelSecurity",
437
+ /ALTER TABLE "public"\."sessions" ENABLE ROW LEVEL SECURITY/.test(
438
+ sql.enableRowLevelSecurity("sessions", { schema: "public", dialect: "postgres" }).sql));
439
+ check("enableRowLevelSecurity force",
440
+ /FORCE ROW LEVEL SECURITY/.test(
441
+ sql.enableRowLevelSecurity("sessions", { dialect: "postgres", force: true }).sql));
442
+ check("disableRowLevelSecurity",
443
+ /DISABLE ROW LEVEL SECURITY/.test(
444
+ sql.disableRowLevelSecurity("sessions", { dialect: "postgres" }).sql));
445
+ var pol = sql.createPolicy("tenant_iso", "sessions", {
446
+ role: "app_user", command: "ALL",
447
+ using: "tenant_id = current_setting('app.tenant_id')::uuid",
448
+ withCheck: "tenant_id = current_setting('app.tenant_id')::uuid",
449
+ }, { schema: "public", dialect: "postgres" });
450
+ check("createPolicy canonical clause order",
451
+ /CREATE POLICY "tenant_iso" ON "public"\."sessions" AS PERMISSIVE FOR ALL TO "app_user" USING \(/.test(pol.sql) &&
452
+ /WITH CHECK \(/.test(pol.sql));
453
+ check("dropPolicy IF EXISTS",
454
+ /DROP POLICY IF EXISTS "tenant_iso" ON "public"\."sessions"/.test(
455
+ sql.dropPolicy("tenant_iso", "sessions", { schema: "public", dialect: "postgres" }).sql));
456
+ rejects("createPolicy requires using", function () {
457
+ return sql.createPolicy("p", "t", { command: "ALL" }, { dialect: "postgres" });
458
+ }, "sql-builder/bad-rls-predicate");
459
+ rejects("enableRowLevelSecurity refused on sqlite", function () {
460
+ return sql.enableRowLevelSecurity("t", { dialect: "sqlite" });
461
+ }, "sql-builder/rls-postgres-only");
462
+
463
+ // ---- catalog / pragma audited sub-API (sqlite-internal) ----
464
+ check("catalog.listTables",
465
+ /SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'/.test(
466
+ sql.catalog.listTables().sql));
467
+ check("catalog.tableExists binds name",
468
+ sql.catalog.tableExists("audit_log").params[0] === "audit_log");
469
+ check("catalog.tableInfo quotes name",
470
+ /PRAGMA table_info\("audit_log"\)/.test(sql.catalog.tableInfo("audit_log").sql));
471
+ check("catalog.sampleRandom ORDER BY RANDOM",
472
+ /ORDER BY RANDOM\(\) LIMIT \?/.test(sql.catalog.sampleRandom("t", ["a"], { limit: 5 }).sql));
473
+ check("catalog.changes", sql.catalog.changes().sql === "SELECT changes() AS c");
474
+ check("pragma journal_mode set", sql.pragma("journal_mode", "WAL").sql === "PRAGMA journal_mode=WAL");
475
+ check("pragma journal_mode read", sql.pragma("journal_mode").sql === "PRAGMA journal_mode");
476
+ check("pragma wal_checkpoint", sql.pragma("wal_checkpoint", "TRUNCATE").sql === "PRAGMA wal_checkpoint(TRUNCATE)");
477
+ rejects("pragma rejects off-allowlist verb", function () { return sql.pragma("user_version", 5); },
478
+ "sql-builder/bad-pragma");
479
+ rejects("pragma rejects off-vocabulary arg", function () { return sql.pragma("journal_mode", "EVIL"); },
480
+ "sql-builder/bad-pragma-arg");
481
+
482
+ // ---- selectRaw projection (presence sentinel) ----
483
+ var probe = sql.select("t", { dialect: "postgres" }).selectRaw("1").where("id", 1).toExternalSql("postgres");
484
+ check("selectRaw 1 presence probe", /^SELECT 1 FROM t WHERE "id" = \$1$/.test(probe.sql));
485
+
486
+ // ---- sqlite FTS5 virtual table DDL (createVirtualTable) ----
487
+ var vt = sql.createVirtualTable("mail_fts", {
488
+ columns: [{ name: "objectid", unindexed: true }, "subject_toks", "body_toks"],
489
+ tokenize: "unicode61 remove_diacritics 2",
490
+ });
491
+ check("createVirtualTable emits USING fts5 with quoted cols + tokenize",
492
+ vt.sql === 'CREATE VIRTUAL TABLE IF NOT EXISTS "mail_fts" USING fts5(' +
493
+ '"objectid" UNINDEXED, "subject_toks", "body_toks", ' +
494
+ "tokenize = 'unicode61 remove_diacritics 2')");
495
+ rejects("createVirtualTable refused on non-sqlite", function () {
496
+ return sql.createVirtualTable("x", { columns: ["a"], dialect: "postgres" });
497
+ }, "sql-builder/vtable-sqlite-only");
498
+ rejects("createVirtualTable refuses loadable tokenizer", function () {
499
+ return sql.createVirtualTable("x", { columns: ["a"], tokenize: "evil_loadable" });
500
+ }, "sql-builder/bad-tokenize");
501
+ rejects("createVirtualTable refuses off-allowlist tokenize arg", function () {
502
+ return sql.createVirtualTable("x", { columns: ["a"], tokenize: "unicode61 DROP" });
503
+ }, "sql-builder/bad-tokenize");
504
+ rejects("createVirtualTable refuses unknown per-column option", function () {
505
+ return sql.createVirtualTable("x", { columns: [{ name: "a", evil: 1 }] });
506
+ }, "sql-builder/bad-vtable-column");
507
+
508
+ // ---- FTS5 MATCH (whereMatch) — operand always binds as a single ? ----
509
+ var m = sql.select("mail_fts", { dialect: "sqlite" }).columns(["objectid"])
510
+ .whereMatch("mail_fts", "hashA hashB").toSql();
511
+ check("whereMatch emits <table> MATCH ? binding the query string",
512
+ m.sql === 'SELECT "objectid" FROM mail_fts WHERE "mail_fts" MATCH ?' &&
513
+ m.params.length === 1 && m.params[0] === "hashA hashB");
514
+ rejects("whereMatch refused on postgres", function () {
515
+ return sql.select("t", { dialect: "postgres" }).columns(["id"]).whereMatch("t", "x").toSql();
516
+ }, "sql-builder/match-sqlite-only");
517
+ rejects("whereMatch refuses empty query", function () {
518
+ return sql.select("t", { dialect: "sqlite" }).columns(["id"]).whereMatch("t", "").toSql();
519
+ }, "sql-builder/bad-match");
520
+
521
+ // ---- json_each membership (whereInJsonEach) — JSON-array string binds as one ? ----
522
+ var je = sql.select("msgs", { dialect: "sqlite" }).columns(["objectid", "folder_id"])
523
+ .where("folder_id", 1).whereInJsonEach("objectid", '["a","b"]').toSql();
524
+ check("whereInJsonEach emits IN (SELECT value FROM json_each(?))",
525
+ je.sql.indexOf('"objectid" IN (SELECT value FROM json_each(?))') !== -1 &&
526
+ je.params.length === 2 && je.params[1] === '["a","b"]');
527
+ rejects("whereInJsonEach refused on postgres", function () {
528
+ return sql.select("t", { dialect: "postgres" }).columns(["id"]).whereInJsonEach("id", "[]").toSql();
529
+ }, "sql-builder/json-each-sqlite-only");
530
+
531
+ // ---- the composed mail-store search shape: FTS subquery driving an
532
+ // outer SELECT via whereIn(col, subBuilder) ----
533
+ var ftsSub = sql.select("mail_fts", { dialect: "sqlite" }).columns(["objectid"])
534
+ .whereMatch("mail_fts", "tok1 tok2");
535
+ var search = sql.select("msgs", { dialect: "sqlite" }).columns(["objectid", "modseq"])
536
+ .where("folder_id", 1).whereOp("modseq", ">", 5).whereIn("objectid", ftsSub)
537
+ .orderBy("modseq").limit(50).toSql();
538
+ check("FTS subquery composes into outer whereIn with one MATCH bind + folder/modseq binds",
539
+ /MATCH \?\) ORDER BY "modseq" ASC LIMIT 50$/.test(search.sql) &&
540
+ search.params.length === 3 &&
541
+ search.params[0] === 1 && search.params[1] === 5 && search.params[2] === "tok1 tok2");
542
+
543
+ // ---- v0.15.3 DDL hardening ----
544
+ // #105 verbatim column type: the one raw-emission position in the builder.
545
+ // Injection safety is enforced at the statement level — createTable routes the
546
+ // finished DDL through the quote-aware _assertCatalogEmittable, which refuses a
547
+ // top-level ';' / comment / unbalanced quote / unbalanced paren while allowing
548
+ // those characters INSIDE a balanced quoted label (so MySQL ENUM/SET pass).
549
+ rejects("createTable refuses a verbatim type that stacks a statement", function () {
550
+ return sql.createTable("t", [{ name: "id", type: "int" },
551
+ { name: "evil", type: "text); DROP TABLE secrets; --" }], { dialect: "postgres" });
552
+ }, "sql-builder/stacked-statement");
553
+ rejects("createTable refuses a verbatim type with an unbalanced quote (catalog gate)", function () {
554
+ return sql.createTable("t", [{ name: "c", type: "text'" }], { dialect: "postgres" });
555
+ }, "sql-builder/unterminated-quote");
556
+ check("createTable allows a MySQL ENUM type (balanced quotes, the verbatim fallthrough)",
557
+ sql.createTable("t", [{ name: "id", type: "int" }, { name: "status", type: "ENUM('active','inactive')" }],
558
+ { dialect: "mysql" }).sql.indexOf("ENUM('active','inactive')") !== -1);
559
+ check("createTable allows a marker (;/--) INSIDE a balanced ENUM label (quote-aware gate, not over-rejected)",
560
+ sql.createTable("t", [{ name: "id", type: "int" }, { name: "status", type: "ENUM('needs;review','a--b')" }],
561
+ { dialect: "mysql" }).sql.indexOf("ENUM('needs;review','a--b')") !== -1);
562
+ check("createTable allows a legit multi-word verbatim type (DOUBLE PRECISION)",
563
+ sql.createTable("t", [{ name: "id", type: "int" }, { name: "p", type: "DOUBLE PRECISION" }],
564
+ { dialect: "postgres" }).sql.indexOf("DOUBLE PRECISION") !== -1);
565
+ check("createTable allows a parameterised verbatim type (VARCHAR(255))",
566
+ sql.createTable("t", [{ name: "s", type: "VARCHAR(255)" }], { dialect: "postgres" })
567
+ .sql.indexOf("VARCHAR(255)") !== -1);
568
+
569
+ // #118 a column-level primary key and a composite opts.primaryKey are exclusive.
570
+ rejects("createTable refuses a column PK plus a composite opts.primaryKey", function () {
571
+ return sql.createTable("t", [{ name: "id", autoIncrement: true }, { name: "k", type: "text" }],
572
+ { dialect: "sqlite", primaryKey: ["id", "k"] });
573
+ }, "sql-builder/bad-column");
574
+ check("createTable allows a composite opts.primaryKey with no column-level PK",
575
+ sql.createTable("t", [{ name: "a", type: "int" }, { name: "b", type: "int" }],
576
+ { dialect: "sqlite", primaryKey: ["a", "b"] }).sql.indexOf('PRIMARY KEY ("a", "b")') !== -1);
577
+
578
+ // #119 upsert readback resolves the conflict-key cell instead of binding a wrapper.
579
+ rejects("upsert readback refuses a server-evaluated function conflict key", function () {
580
+ return sql.upsert("t", { dialect: "mysql" }).values({ id: sql.fn("CURRENT_TIMESTAMP"), c: 1 })
581
+ .onConflict(["id"]).doUpdateFromExcluded(["c"]).returning(["c"]).toSql();
582
+ }, "sql-builder/bad-conflict");
583
+ var rbScalar = sql.upsert("t", { dialect: "mysql" }).values({ id: 5, c: 1 })
584
+ .onConflict(["id"]).doUpdateFromExcluded(["c"]).returning(["c"]).toSql();
585
+ check("upsert readback binds a plain scalar conflict key unchanged",
586
+ rbScalar.readbackSql && rbScalar.readbackSql.params.length === 1 &&
587
+ rbScalar.readbackSql.params[0] === 5);
588
+ var rbCast = sql.upsert("t", { dialect: "mysql" }).values({ id: sql.cast("42", "int"), c: 1 })
589
+ .onConflict(["id"]).doUpdateFromExcluded(["c"]).returning(["c"]).toSql();
590
+ check("upsert readback renders a cast conflict key (CAST) binding the inner value, not the wrapper",
591
+ rbCast.readbackSql && rbCast.readbackSql.sql.indexOf("CAST(") !== -1 &&
592
+ rbCast.readbackSql.params.length === 1 && rbCast.readbackSql.params[0] === "42");
593
+ }
594
+
595
+ module.exports = { run: run };