@emilia-protocol/gate 0.10.0 → 0.13.0

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 (419) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +272 -0
  3. package/action-control-manifest.js +3 -268
  4. package/action-escrow-custodian.js +4 -0
  5. package/action-escrow-evidence.js +4 -0
  6. package/action-escrow-package.js +4 -0
  7. package/action-escrow-postgres.js +4 -0
  8. package/action-escrow-state.js +4 -0
  9. package/action-escrow-verifiers.js +4 -0
  10. package/action-escrow.js +4 -0
  11. package/action-packs.js +3 -140
  12. package/adapters/_kit.js +3 -104
  13. package/adapters/aws.js +3 -108
  14. package/adapters/cloudflare.js +3 -54
  15. package/adapters/gcp.js +3 -70
  16. package/adapters/github.js +3 -109
  17. package/adapters/jira.js +3 -55
  18. package/adapters/k8s.js +3 -70
  19. package/adapters/linear.js +3 -55
  20. package/adapters/salesforce.js +3 -55
  21. package/adapters/stripe.js +3 -81
  22. package/adapters/supabase.js +3 -121
  23. package/adapters/terraform.js +3 -59
  24. package/adapters/vercel.js +3 -84
  25. package/aec-execution.js +3 -312
  26. package/breakglass.js +3 -582
  27. package/capability-receipt.js +4 -0
  28. package/cf1-conformance.js +3 -106
  29. package/challenge-store.js +3 -69
  30. package/control-plane.js +3 -340
  31. package/coverage.js +3 -721
  32. package/demo.mjs +1 -1
  33. package/deployment-attestation.js +3 -247
  34. package/dist/action-control-manifest.d.ts +82 -0
  35. package/dist/action-control-manifest.d.ts.map +1 -0
  36. package/dist/action-control-manifest.js +422 -0
  37. package/dist/action-control-manifest.js.map +1 -0
  38. package/dist/action-escrow-custodian.d.ts +74 -0
  39. package/dist/action-escrow-custodian.d.ts.map +1 -0
  40. package/dist/action-escrow-custodian.js +363 -0
  41. package/dist/action-escrow-custodian.js.map +1 -0
  42. package/dist/action-escrow-evidence.d.ts +130 -0
  43. package/dist/action-escrow-evidence.d.ts.map +1 -0
  44. package/dist/action-escrow-evidence.js +1012 -0
  45. package/dist/action-escrow-evidence.js.map +1 -0
  46. package/dist/action-escrow-package.d.ts +10 -0
  47. package/dist/action-escrow-package.d.ts.map +1 -0
  48. package/dist/action-escrow-package.js +1583 -0
  49. package/dist/action-escrow-package.js.map +1 -0
  50. package/dist/action-escrow-postgres.d.ts +62 -0
  51. package/dist/action-escrow-postgres.d.ts.map +1 -0
  52. package/dist/action-escrow-postgres.js +339 -0
  53. package/dist/action-escrow-postgres.js.map +1 -0
  54. package/dist/action-escrow-state.d.ts +141 -0
  55. package/dist/action-escrow-state.d.ts.map +1 -0
  56. package/dist/action-escrow-state.js +413 -0
  57. package/dist/action-escrow-state.js.map +1 -0
  58. package/dist/action-escrow-verifiers.d.ts +65 -0
  59. package/dist/action-escrow-verifiers.d.ts.map +1 -0
  60. package/dist/action-escrow-verifiers.js +421 -0
  61. package/dist/action-escrow-verifiers.js.map +1 -0
  62. package/dist/action-escrow.d.ts +112 -0
  63. package/dist/action-escrow.d.ts.map +1 -0
  64. package/dist/action-escrow.js +2661 -0
  65. package/dist/action-escrow.js.map +1 -0
  66. package/dist/action-packs.d.ts +54 -0
  67. package/dist/action-packs.d.ts.map +1 -0
  68. package/dist/action-packs.js +143 -0
  69. package/dist/action-packs.js.map +1 -0
  70. package/dist/adapters/_kit.d.ts +50 -0
  71. package/dist/adapters/_kit.d.ts.map +1 -0
  72. package/dist/adapters/_kit.js +98 -0
  73. package/dist/adapters/_kit.js.map +1 -0
  74. package/dist/adapters/aws.d.ts +158 -0
  75. package/dist/adapters/aws.d.ts.map +1 -0
  76. package/dist/adapters/aws.js +136 -0
  77. package/dist/adapters/aws.js.map +1 -0
  78. package/dist/adapters/cloudflare.d.ts +116 -0
  79. package/dist/adapters/cloudflare.d.ts.map +1 -0
  80. package/dist/adapters/cloudflare.js +75 -0
  81. package/dist/adapters/cloudflare.js.map +1 -0
  82. package/dist/adapters/gcp.d.ts +139 -0
  83. package/dist/adapters/gcp.d.ts.map +1 -0
  84. package/dist/adapters/gcp.js +69 -0
  85. package/dist/adapters/gcp.js.map +1 -0
  86. package/dist/adapters/github.d.ts +123 -0
  87. package/dist/adapters/github.d.ts.map +1 -0
  88. package/dist/adapters/github.js +105 -0
  89. package/dist/adapters/github.js.map +1 -0
  90. package/dist/adapters/jira.d.ts +109 -0
  91. package/dist/adapters/jira.d.ts.map +1 -0
  92. package/dist/adapters/jira.js +54 -0
  93. package/dist/adapters/jira.js.map +1 -0
  94. package/dist/adapters/k8s.d.ts +139 -0
  95. package/dist/adapters/k8s.d.ts.map +1 -0
  96. package/dist/adapters/k8s.js +69 -0
  97. package/dist/adapters/k8s.js.map +1 -0
  98. package/dist/adapters/linear.d.ts +109 -0
  99. package/dist/adapters/linear.d.ts.map +1 -0
  100. package/dist/adapters/linear.js +54 -0
  101. package/dist/adapters/linear.js.map +1 -0
  102. package/dist/adapters/salesforce.d.ts +109 -0
  103. package/dist/adapters/salesforce.d.ts.map +1 -0
  104. package/dist/adapters/salesforce.js +54 -0
  105. package/dist/adapters/salesforce.js.map +1 -0
  106. package/dist/adapters/stripe.d.ts +116 -0
  107. package/dist/adapters/stripe.d.ts.map +1 -0
  108. package/dist/adapters/stripe.js +77 -0
  109. package/dist/adapters/stripe.js.map +1 -0
  110. package/dist/adapters/supabase.d.ts +127 -0
  111. package/dist/adapters/supabase.d.ts.map +1 -0
  112. package/dist/adapters/supabase.js +112 -0
  113. package/dist/adapters/supabase.js.map +1 -0
  114. package/dist/adapters/terraform.d.ts +109 -0
  115. package/dist/adapters/terraform.d.ts.map +1 -0
  116. package/dist/adapters/terraform.js +58 -0
  117. package/dist/adapters/terraform.js.map +1 -0
  118. package/dist/adapters/vercel.d.ts +114 -0
  119. package/dist/adapters/vercel.d.ts.map +1 -0
  120. package/dist/adapters/vercel.js +81 -0
  121. package/dist/adapters/vercel.js.map +1 -0
  122. package/dist/aec-execution.d.ts +107 -0
  123. package/dist/aec-execution.d.ts.map +1 -0
  124. package/dist/aec-execution.js +334 -0
  125. package/dist/aec-execution.js.map +1 -0
  126. package/dist/breakglass.d.ts +205 -0
  127. package/dist/breakglass.d.ts.map +1 -0
  128. package/dist/breakglass.js +627 -0
  129. package/dist/breakglass.js.map +1 -0
  130. package/dist/capability-receipt.d.ts +601 -0
  131. package/dist/capability-receipt.d.ts.map +1 -0
  132. package/dist/capability-receipt.js +1177 -0
  133. package/dist/capability-receipt.js.map +1 -0
  134. package/dist/cf1-conformance.d.ts +83 -0
  135. package/dist/cf1-conformance.d.ts.map +1 -0
  136. package/dist/cf1-conformance.js +94 -0
  137. package/dist/cf1-conformance.js.map +1 -0
  138. package/dist/challenge-store.d.ts +20 -0
  139. package/dist/challenge-store.d.ts.map +1 -0
  140. package/dist/challenge-store.js +62 -0
  141. package/dist/challenge-store.js.map +1 -0
  142. package/dist/control-plane.d.ts +136 -0
  143. package/dist/control-plane.d.ts.map +1 -0
  144. package/dist/control-plane.js +349 -0
  145. package/dist/control-plane.js.map +1 -0
  146. package/dist/coverage.d.ts +156 -0
  147. package/dist/coverage.d.ts.map +1 -0
  148. package/dist/coverage.js +768 -0
  149. package/dist/coverage.js.map +1 -0
  150. package/dist/deployment-attestation.d.ts +93 -0
  151. package/dist/deployment-attestation.d.ts.map +1 -0
  152. package/dist/deployment-attestation.js +262 -0
  153. package/dist/deployment-attestation.js.map +1 -0
  154. package/dist/eg1-conformance.d.ts +286 -0
  155. package/dist/eg1-conformance.d.ts.map +1 -0
  156. package/dist/eg1-conformance.js +379 -0
  157. package/dist/eg1-conformance.js.map +1 -0
  158. package/dist/enterprise.d.ts +88 -0
  159. package/dist/enterprise.d.ts.map +1 -0
  160. package/dist/enterprise.js +194 -0
  161. package/dist/enterprise.js.map +1 -0
  162. package/dist/evidence-postgres.d.ts +123 -0
  163. package/dist/evidence-postgres.d.ts.map +1 -0
  164. package/dist/evidence-postgres.js +343 -0
  165. package/dist/evidence-postgres.js.map +1 -0
  166. package/dist/evidence.d.ts +113 -0
  167. package/dist/evidence.d.ts.map +1 -0
  168. package/dist/evidence.js +369 -0
  169. package/dist/evidence.js.map +1 -0
  170. package/dist/execution-binding.d.ts +49 -0
  171. package/dist/execution-binding.d.ts.map +1 -0
  172. package/dist/execution-binding.js +243 -0
  173. package/dist/execution-binding.js.map +1 -0
  174. package/dist/formal-runtime-map.d.ts +42 -0
  175. package/dist/formal-runtime-map.d.ts.map +1 -0
  176. package/dist/formal-runtime-map.js +23 -0
  177. package/dist/formal-runtime-map.js.map +1 -0
  178. package/dist/index.d.ts +1002 -0
  179. package/dist/index.d.ts.map +1 -0
  180. package/dist/index.js +1736 -0
  181. package/dist/index.js.map +1 -0
  182. package/dist/key-registry.d.ts +60 -0
  183. package/dist/key-registry.d.ts.map +1 -0
  184. package/dist/key-registry.js +144 -0
  185. package/dist/key-registry.js.map +1 -0
  186. package/dist/mcp.d.ts +53 -0
  187. package/dist/mcp.d.ts.map +1 -0
  188. package/dist/mcp.js +112 -0
  189. package/dist/mcp.js.map +1 -0
  190. package/dist/metering.d.ts +80 -0
  191. package/dist/metering.d.ts.map +1 -0
  192. package/dist/metering.js +227 -0
  193. package/dist/metering.js.map +1 -0
  194. package/dist/metrics.d.ts +68 -0
  195. package/dist/metrics.d.ts.map +1 -0
  196. package/dist/metrics.js +242 -0
  197. package/dist/metrics.js.map +1 -0
  198. package/dist/network-witness.d.ts +167 -0
  199. package/dist/network-witness.d.ts.map +1 -0
  200. package/dist/network-witness.js +520 -0
  201. package/dist/network-witness.js.map +1 -0
  202. package/dist/protocol-state.d.ts +141 -0
  203. package/dist/protocol-state.d.ts.map +1 -0
  204. package/dist/protocol-state.js +106 -0
  205. package/dist/protocol-state.js.map +1 -0
  206. package/dist/receipt-program.d.ts +59 -0
  207. package/dist/receipt-program.d.ts.map +1 -0
  208. package/dist/receipt-program.js +1053 -0
  209. package/dist/receipt-program.js.map +1 -0
  210. package/dist/reliance-kernel.d.ts +66 -0
  211. package/dist/reliance-kernel.d.ts.map +1 -0
  212. package/dist/reliance-kernel.js +103 -0
  213. package/dist/reliance-kernel.js.map +1 -0
  214. package/dist/reliance-packet.d.ts +67 -0
  215. package/dist/reliance-packet.d.ts.map +1 -0
  216. package/dist/reliance-packet.js +176 -0
  217. package/dist/reliance-packet.js.map +1 -0
  218. package/dist/remedy-program-postgres.d.ts +37 -0
  219. package/dist/remedy-program-postgres.d.ts.map +1 -0
  220. package/dist/remedy-program-postgres.js +291 -0
  221. package/dist/remedy-program-postgres.js.map +1 -0
  222. package/dist/remedy-program-receipt.d.ts +97 -0
  223. package/dist/remedy-program-receipt.d.ts.map +1 -0
  224. package/dist/remedy-program-receipt.js +817 -0
  225. package/dist/remedy-program-receipt.js.map +1 -0
  226. package/dist/remedy-program.d.ts +76 -0
  227. package/dist/remedy-program.d.ts.map +1 -0
  228. package/dist/remedy-program.js +1346 -0
  229. package/dist/remedy-program.js.map +1 -0
  230. package/dist/reports/art14.d.ts +101 -0
  231. package/dist/reports/art14.d.ts.map +1 -0
  232. package/dist/reports/art14.js +340 -0
  233. package/dist/reports/art14.js.map +1 -0
  234. package/dist/reports/assurance-package.d.ts +197 -0
  235. package/dist/reports/assurance-package.d.ts.map +1 -0
  236. package/dist/reports/assurance-package.js +313 -0
  237. package/dist/reports/assurance-package.js.map +1 -0
  238. package/dist/reports/auditor-workpaper.d.ts +194 -0
  239. package/dist/reports/auditor-workpaper.d.ts.map +1 -0
  240. package/dist/reports/auditor-workpaper.js +545 -0
  241. package/dist/reports/auditor-workpaper.js.map +1 -0
  242. package/dist/reports/external-verification.d.ts +76 -0
  243. package/dist/reports/external-verification.d.ts.map +1 -0
  244. package/dist/reports/external-verification.js +209 -0
  245. package/dist/reports/external-verification.js.map +1 -0
  246. package/dist/reports/reperform.d.ts +122 -0
  247. package/dist/reports/reperform.d.ts.map +1 -0
  248. package/dist/reports/reperform.js +432 -0
  249. package/dist/reports/reperform.js.map +1 -0
  250. package/dist/reports/underwriter.d.ts +127 -0
  251. package/dist/reports/underwriter.d.ts.map +1 -0
  252. package/dist/reports/underwriter.js +348 -0
  253. package/dist/reports/underwriter.js.map +1 -0
  254. package/dist/retention.d.ts +88 -0
  255. package/dist/retention.d.ts.map +1 -0
  256. package/dist/retention.js +90 -0
  257. package/dist/retention.js.map +1 -0
  258. package/dist/roster.d.ts +113 -0
  259. package/dist/roster.d.ts.map +1 -0
  260. package/dist/roster.js +261 -0
  261. package/dist/roster.js.map +1 -0
  262. package/dist/runtime-monitor.d.ts +132 -0
  263. package/dist/runtime-monitor.d.ts.map +1 -0
  264. package/dist/runtime-monitor.js +197 -0
  265. package/dist/runtime-monitor.js.map +1 -0
  266. package/dist/settlement.d.ts +68 -0
  267. package/dist/settlement.d.ts.map +1 -0
  268. package/dist/settlement.js +306 -0
  269. package/dist/settlement.js.map +1 -0
  270. package/dist/siem.d.ts +261 -0
  271. package/dist/siem.d.ts.map +1 -0
  272. package/dist/siem.js +247 -0
  273. package/dist/siem.js.map +1 -0
  274. package/dist/store-postgres.d.ts +107 -0
  275. package/dist/store-postgres.d.ts.map +1 -0
  276. package/dist/store-postgres.js +152 -0
  277. package/dist/store-postgres.js.map +1 -0
  278. package/dist/store.d.ts +95 -0
  279. package/dist/store.d.ts.map +1 -0
  280. package/dist/store.js +202 -0
  281. package/dist/store.js.map +1 -0
  282. package/dist/strict-json.d.ts +14 -0
  283. package/dist/strict-json.d.ts.map +1 -0
  284. package/dist/strict-json.js +132 -0
  285. package/dist/strict-json.js.map +1 -0
  286. package/dist/trust-program-adapters.d.ts +122 -0
  287. package/dist/trust-program-adapters.d.ts.map +1 -0
  288. package/dist/trust-program-adapters.js +802 -0
  289. package/dist/trust-program-adapters.js.map +1 -0
  290. package/dist/trust-program-postgres.d.ts +41 -0
  291. package/dist/trust-program-postgres.d.ts.map +1 -0
  292. package/dist/trust-program-postgres.js +346 -0
  293. package/dist/trust-program-postgres.js.map +1 -0
  294. package/dist/trust-program-revocation.d.ts +206 -0
  295. package/dist/trust-program-revocation.d.ts.map +1 -0
  296. package/dist/trust-program-revocation.js +600 -0
  297. package/dist/trust-program-revocation.js.map +1 -0
  298. package/dist/trust-program.d.ts +197 -0
  299. package/dist/trust-program.d.ts.map +1 -0
  300. package/dist/trust-program.js +1351 -0
  301. package/dist/trust-program.js.map +1 -0
  302. package/dist/witness-postgres.d.ts +43 -0
  303. package/dist/witness-postgres.d.ts.map +1 -0
  304. package/dist/witness-postgres.js +92 -0
  305. package/dist/witness-postgres.js.map +1 -0
  306. package/dist/zk-range-proof.d.ts +78 -0
  307. package/dist/zk-range-proof.d.ts.map +1 -0
  308. package/dist/zk-range-proof.js +228 -0
  309. package/dist/zk-range-proof.js.map +1 -0
  310. package/eg1-conformance.js +3 -404
  311. package/enterprise.js +3 -180
  312. package/ep-assure.mjs +1 -0
  313. package/evidence-postgres.js +3 -356
  314. package/evidence.js +4 -360
  315. package/execution-binding.js +3 -212
  316. package/formal-runtime-map.js +4 -0
  317. package/index.js +4 -1249
  318. package/key-registry.js +3 -134
  319. package/mcp.js +3 -109
  320. package/metering.js +3 -226
  321. package/metrics.js +3 -231
  322. package/network-witness.js +3 -499
  323. package/package.json +47 -4
  324. package/receipt-program.js +4 -0
  325. package/reliance-kernel.js +3 -112
  326. package/reliance-packet.js +3 -175
  327. package/remedy-program-postgres.js +4 -0
  328. package/remedy-program-receipt.js +4 -0
  329. package/remedy-program.js +4 -0
  330. package/reports/art14.js +0 -0
  331. package/reports/assurance-package.js +2 -312
  332. package/reports/auditor-workpaper.js +3 -537
  333. package/reports/external-verification.js +3 -222
  334. package/reports/reperform.js +3 -424
  335. package/reports/underwriter.js +3 -339
  336. package/retention.js +3 -84
  337. package/roster.js +3 -264
  338. package/runtime-monitor.js +4 -0
  339. package/settlement.js +3 -299
  340. package/siem.js +3 -235
  341. package/src/action-control-manifest.ts +424 -0
  342. package/src/action-escrow-custodian.ts +427 -0
  343. package/src/action-escrow-evidence.ts +1178 -0
  344. package/src/action-escrow-package.ts +1821 -0
  345. package/src/action-escrow-postgres.ts +366 -0
  346. package/src/action-escrow-state.ts +498 -0
  347. package/src/action-escrow-verifiers.ts +484 -0
  348. package/src/action-escrow.ts +3039 -0
  349. package/src/action-packs.ts +170 -0
  350. package/src/adapters/_kit.ts +117 -0
  351. package/src/adapters/aws.ts +142 -0
  352. package/src/adapters/cloudflare.ts +78 -0
  353. package/src/adapters/gcp.ts +71 -0
  354. package/src/adapters/github.ts +110 -0
  355. package/src/adapters/jira.ts +56 -0
  356. package/src/adapters/k8s.ts +71 -0
  357. package/src/adapters/linear.ts +56 -0
  358. package/src/adapters/salesforce.ts +56 -0
  359. package/src/adapters/stripe.ts +82 -0
  360. package/src/adapters/supabase.ts +122 -0
  361. package/src/adapters/terraform.ts +60 -0
  362. package/src/adapters/vercel.ts +85 -0
  363. package/src/aec-execution.ts +354 -0
  364. package/src/breakglass.ts +647 -0
  365. package/src/capability-receipt.ts +1258 -0
  366. package/src/cf1-conformance.ts +120 -0
  367. package/src/challenge-store.ts +70 -0
  368. package/src/control-plane.ts +374 -0
  369. package/src/coverage.ts +832 -0
  370. package/src/deployment-attestation.ts +259 -0
  371. package/src/eg1-conformance.ts +471 -0
  372. package/src/enterprise.ts +195 -0
  373. package/src/evidence-postgres.ts +374 -0
  374. package/src/evidence.ts +367 -0
  375. package/src/execution-binding.ts +236 -0
  376. package/src/formal-runtime-map.ts +24 -0
  377. package/src/index.ts +2122 -0
  378. package/src/key-registry.ts +150 -0
  379. package/src/mcp.ts +120 -0
  380. package/src/metering.ts +237 -0
  381. package/src/metrics.ts +232 -0
  382. package/src/network-witness.ts +585 -0
  383. package/src/protocol-state.ts +143 -0
  384. package/src/protocol-state.typecheck.ts +94 -0
  385. package/src/receipt-program.ts +1105 -0
  386. package/src/reliance-kernel.ts +119 -0
  387. package/src/reliance-packet.ts +206 -0
  388. package/src/remedy-program-postgres.ts +367 -0
  389. package/src/remedy-program-receipt.ts +891 -0
  390. package/src/remedy-program.ts +1388 -0
  391. package/src/reports/art14.ts +361 -0
  392. package/src/reports/assurance-package.ts +330 -0
  393. package/src/reports/auditor-workpaper.ts +558 -0
  394. package/src/reports/external-verification.ts +232 -0
  395. package/src/reports/reperform.ts +441 -0
  396. package/src/reports/underwriter.ts +356 -0
  397. package/src/retention.ts +100 -0
  398. package/src/roster.ts +273 -0
  399. package/src/runtime-monitor.ts +217 -0
  400. package/src/settlement.ts +313 -0
  401. package/src/siem.ts +247 -0
  402. package/src/store-postgres.ts +167 -0
  403. package/src/store.ts +214 -0
  404. package/src/strict-json.ts +115 -0
  405. package/src/trust-program-adapters.ts +847 -0
  406. package/src/trust-program-postgres.ts +429 -0
  407. package/src/trust-program-revocation.ts +751 -0
  408. package/src/trust-program.ts +1460 -0
  409. package/src/witness-postgres.ts +106 -0
  410. package/src/zk-range-proof.ts +250 -0
  411. package/store-postgres.js +3 -161
  412. package/store.js +4 -198
  413. package/strict-json.js +3 -85
  414. package/trust-program-adapters.js +4 -0
  415. package/trust-program-postgres.js +4 -0
  416. package/trust-program-revocation.js +4 -0
  417. package/trust-program.js +4 -0
  418. package/witness-postgres.js +3 -96
  419. package/zk-range-proof.js +4 -0
@@ -0,0 +1,106 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Tenant-scoped Postgres sequence store for EP-GATE-NETWORK-WITNESS-v1.
4
+ *
5
+ * The migration owns synchronization and authorization. Runtime callers get
6
+ * EXECUTE on one SECURITY DEFINER function, not INSERT/UPDATE privileges on the
7
+ * checkpoint table. Database ambiguity is allowed to throw so the witness
8
+ * ingestion kernel can fail closed as `sequence_store_unavailable`.
9
+ */
10
+
11
+ export const PG_WITNESS_SEQUENCE_VERSION = 'EP-GATE-PG-WITNESS-SEQUENCE-v1';
12
+ export const WITNESS_CHECKPOINT_FUNCTION = 'emilia_gate_evidence.advance_network_witness_checkpoint';
13
+
14
+ const DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
15
+ const CLOSED_REASONS = new Set(['statement_replay', 'sequence_rollback', 'sequence_equivocation']);
16
+
17
+ export const WITNESS_SEQUENCE_SQL = Object.freeze({
18
+ advance: `SELECT accepted, reason
19
+ FROM ${WITNESS_CHECKPOINT_FUNCTION}($1, $2, $3::bytea, $4::bigint, $5)`,
20
+ });
21
+
22
+ function scopedId(value, label) {
23
+ if (typeof value !== 'string' || value.length === 0 || value.length > 256
24
+ || /[\u0000-\u001f\u007f]/.test(value)) {
25
+ throw new Error(`${label} must be a non-empty control-free string of at most 256 characters`);
26
+ }
27
+ return value;
28
+ }
29
+
30
+ function streamBytes(value) {
31
+ if (typeof value !== 'string' || value.length > 513) {
32
+ throw new Error('witness streamId is invalid');
33
+ }
34
+ const parts = value.split('\0');
35
+ if (parts.length !== 2 || parts.some((part) => part.length === 0 || part.length > 256
36
+ || /[\u0000-\u001f\u007f]/.test(part))) {
37
+ throw new Error('witness streamId must contain one witness-id/capture-point separator');
38
+ }
39
+ return Buffer.from(value, 'utf8');
40
+ }
41
+
42
+ function definitiveRow(result) {
43
+ if (!result || result.rowCount !== 1 || !Array.isArray(result.rows)
44
+ || result.rows.length !== 1 || typeof result.rows[0]?.accepted !== 'boolean') {
45
+ throw new Error('witness checkpoint outcome is unproven');
46
+ }
47
+ const { accepted, reason } = result.rows[0];
48
+ if (accepted) {
49
+ if (reason !== null && reason !== undefined && reason !== '') {
50
+ throw new Error('accepted witness checkpoint carried a refusal reason');
51
+ }
52
+ return { accepted: true, reason: null };
53
+ }
54
+ if (!CLOSED_REASONS.has(reason)) {
55
+ throw new Error('witness checkpoint returned an unknown refusal reason');
56
+ }
57
+ return { accepted: false, reason };
58
+ }
59
+
60
+ /**
61
+ * Create the durable store expected by acceptNetworkWitnessStatement().
62
+ * `query` is a node-postgres style function such as pool.query.bind(pool).
63
+ * @param {{ query?: Function, tenantId?: string|number, gateId?: string|number }} [o]
64
+ */
65
+ export function createPostgresWitnessSequenceStore({
66
+ query,
67
+ tenantId,
68
+ gateId,
69
+ }: {
70
+ query?: (sql: string, params?: any[]) => Promise<any>;
71
+ tenantId?: string | number;
72
+ gateId?: string | number;
73
+ } = {}) {
74
+ if (typeof query !== 'function') {
75
+ throw new Error('createPostgresWitnessSequenceStore: query must be an async pg-style function');
76
+ }
77
+ const tenant = scopedId(tenantId, 'tenantId');
78
+ const gate = scopedId(gateId, 'gateId');
79
+ return Object.freeze({
80
+ durable: true,
81
+ scope: Object.freeze({ tenantId: tenant, gateId: gate }),
82
+ async advance(streamId, sequence, statementDigest) {
83
+ if (!Number.isSafeInteger(sequence) || sequence < 0) {
84
+ throw new Error('witness sequence must be a non-negative safe integer');
85
+ }
86
+ if (typeof statementDigest !== 'string' || !DIGEST_RE.test(statementDigest)) {
87
+ throw new Error('witness statement digest is invalid');
88
+ }
89
+ const result = await query(WITNESS_SEQUENCE_SQL.advance, [
90
+ tenant,
91
+ gate,
92
+ streamBytes(streamId),
93
+ sequence,
94
+ statementDigest,
95
+ ]);
96
+ return definitiveRow(result);
97
+ },
98
+ });
99
+ }
100
+
101
+ export default {
102
+ PG_WITNESS_SEQUENCE_VERSION,
103
+ WITNESS_CHECKPOINT_FUNCTION,
104
+ WITNESS_SEQUENCE_SQL,
105
+ createPostgresWitnessSequenceStore,
106
+ };
@@ -0,0 +1,250 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+
3
+ /**
4
+ * EP-ZK-RANGE-RECEIPT-v1.
5
+ *
6
+ * This is a genuine Bulletproof range proof adapter, not a commitment renamed
7
+ * as zero knowledge. It proves a hidden integer v satisfies 0 <= v <= max by
8
+ * proving ranges for v and max-v, while the second Pedersen commitment is
9
+ * publicly linked to the first. The base EP receipt and its signature remain a
10
+ * separate verification step; this envelope binds only its public digest.
11
+ *
12
+ * The cryptographic engine is intentionally injected/lazy-loaded. The main
13
+ * Gate package does not silently add a 60 MB mobile/WASM dependency. The
14
+ * compatible backend is @aptos-labs/confidential-asset-bindings, which exposes
15
+ * Bulletproofs over Ristretto255. A deployment must pin and audit that optional
16
+ * backend before enabling this path.
17
+ */
18
+
19
+ import { createHash, randomBytes } from 'node:crypto';
20
+ import { ristretto255, ristretto255_hasher } from '@noble/curves/ed25519.js';
21
+ import { canonicalize } from './execution-binding.js';
22
+
23
+ export const ZK_RANGE_RECEIPT_VERSION = 'EP-ZK-RANGE-RECEIPT-v1';
24
+ export const ZK_RANGE_SCHEME = 'Bulletproofs-Ristretto255-range-v1';
25
+ export const ZK_RANGE_BACKEND_PACKAGE = '@aptos-labs/confidential-asset-bindings@1.1.2';
26
+ const ZK_RANGE_BACKEND_MODULE = '@aptos-labs/confidential-asset-bindings';
27
+
28
+ const ORDER = ristretto255.Point.Fn.ORDER;
29
+ const TEXT_ENCODER = new TextEncoder();
30
+
31
+ /**
32
+ * @param {Uint8Array|string} value
33
+ * @param {string} label
34
+ * @param {number|null} [length]
35
+ * @returns {Uint8Array}
36
+ */
37
+ function bytes(value, label, length: number | null = null) {
38
+ const out = value instanceof Uint8Array ? new Uint8Array(value) : Buffer.from(value, 'base64url');
39
+ if (length !== null && out.length !== length) throw new TypeError(`${label} must be ${length} bytes`);
40
+ return out;
41
+ }
42
+
43
+ function b64(value) {
44
+ return Buffer.from(value).toString('base64url');
45
+ }
46
+
47
+ function sha256Hex(value) {
48
+ return createHash('sha256').update(value).digest('hex');
49
+ }
50
+
51
+ function digest(value, label) {
52
+ if (typeof value !== 'string' || !/^sha256:[0-9a-f]{64}$/.test(value)) throw new TypeError(`${label} must be a sha256: digest`);
53
+ return value;
54
+ }
55
+
56
+ function safeU64(value, label) {
57
+ if (!Number.isSafeInteger(value) || value < 0) throw new TypeError(`${label} must be a non-negative safe integer`);
58
+ return value;
59
+ }
60
+
61
+ function rangeBits(max) {
62
+ if (max <= 0xff) return 8;
63
+ if (max <= 0xffff) return 16;
64
+ if (max <= 0xffffffff) return 32;
65
+ return 64;
66
+ }
67
+
68
+ function bytesToBigIntLE(value) {
69
+ let result = 0n;
70
+ for (let i = value.length - 1; i >= 0; i -= 1) result = (result << 8n) | BigInt(value[i]);
71
+ return result;
72
+ }
73
+
74
+ function bigIntToBytesLE(value, length) {
75
+ const out = new Uint8Array(length);
76
+ let current = value;
77
+ for (let i = 0; i < length; i += 1) {
78
+ out[i] = Number(current & 0xffn);
79
+ current >>= 8n;
80
+ }
81
+ return out;
82
+ }
83
+
84
+ function negateScalar(value) {
85
+ const scalar = bytesToBigIntLE(value) % ORDER;
86
+ return bigIntToBytesLE(scalar === 0n ? 0n : ORDER - scalar, 32);
87
+ }
88
+
89
+ /** Derive independent, deterministic Pedersen bases for this proof domain. */
90
+ export function deriveZkRangeBases(domain = ZK_RANGE_RECEIPT_VERSION) {
91
+ if (typeof domain !== 'string' || domain.length === 0) throw new TypeError('ZK range domain is required');
92
+ const valBase = ristretto255.Point.BASE.toBytes();
93
+ const randBase = ristretto255_hasher.hashToCurve(TEXT_ENCODER.encode(`${domain}:randomness-base`)).toBytes();
94
+ if (Buffer.from(valBase).equals(Buffer.from(randBase))) throw new Error('ZK range bases unexpectedly collide');
95
+ return { valBase, randBase };
96
+ }
97
+
98
+ /** Lazy-load the audited/pinned optional Bulletproof WASM binding. */
99
+ export async function loadBulletproofBackend() {
100
+ try {
101
+ // Keep the backend genuinely optional at bundle time. Server deployments
102
+ // that enable ZK install the pinned module explicitly; default Gate builds
103
+ // must not fail or pull the WASM/mobile distribution into every route.
104
+ return await import(/* webpackIgnore: true */ ZK_RANGE_BACKEND_MODULE);
105
+ } catch {
106
+ throw new Error(`ZK range backend unavailable; install ${ZK_RANGE_BACKEND_PACKAGE} explicitly before enabling this path`);
107
+ }
108
+ }
109
+
110
+ function requireBackend(backend) {
111
+ if (!backend || typeof backend.batchRangeProof !== 'function' || typeof backend.batchVerifyProof !== 'function') {
112
+ throw new TypeError('ZK range backend must implement batchRangeProof() and batchVerifyProof()');
113
+ }
114
+ return backend;
115
+ }
116
+
117
+ function linkedSecondCommitment(max, first, valBase) {
118
+ const valueBase = ristretto255.Point.fromBytes(valBase);
119
+ const firstPoint = ristretto255.Point.fromBytes(first);
120
+ return valueBase.multiply(BigInt(max)).subtract(firstPoint).toBytes();
121
+ }
122
+
123
+ function equalBytes(left, right) {
124
+ return left.length === right.length && Buffer.from(left).equals(Buffer.from(right));
125
+ }
126
+
127
+ function publicStatement({ policyHash, actionPredicate, max, baseReceiptDigest, issuerPublicKey, numBits }) {
128
+ return {
129
+ policy_hash: digest(policyHash, 'policy_hash'),
130
+ action_predicate: actionPredicate,
131
+ max,
132
+ base_receipt_digest: digest(baseReceiptDigest, 'base_receipt_digest'),
133
+ issuer_public_key: issuerPublicKey,
134
+ num_bits: numBits,
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Mint a hidden-amount Bulletproof range receipt.
140
+ * @param {{ value?: any, max?: any, blindingFactor?: any, policyHash?: any, actionPredicate?: any, baseReceiptDigest?: any, issuerPublicKey?: any, nonce?: string, domain?: string, backend?: any }} [options]
141
+ */
142
+ export async function mintZkRangeReceipt({
143
+ value,
144
+ max,
145
+ blindingFactor = randomBytes(32),
146
+ policyHash,
147
+ actionPredicate,
148
+ baseReceiptDigest,
149
+ issuerPublicKey,
150
+ nonce = randomBytes(16).toString('base64url'),
151
+ domain = ZK_RANGE_RECEIPT_VERSION,
152
+ backend = null,
153
+ }: {
154
+ value?: number;
155
+ max?: number;
156
+ blindingFactor?: Uint8Array | string;
157
+ policyHash?: string;
158
+ actionPredicate?: string;
159
+ baseReceiptDigest?: string;
160
+ issuerPublicKey?: string;
161
+ nonce?: string;
162
+ domain?: string;
163
+ backend?: { batchRangeProof?: Function; batchVerifyProof?: Function } | null;
164
+ } = {}) {
165
+ const hiddenValue = safeU64(value, 'value');
166
+ const upperBound = safeU64(max, 'max');
167
+ if (hiddenValue > upperBound) throw new TypeError('value exceeds the public range bound');
168
+ if (typeof actionPredicate !== 'string' || actionPredicate.length === 0) throw new TypeError('actionPredicate is required');
169
+ if (typeof issuerPublicKey !== 'string' || issuerPublicKey.length === 0) throw new TypeError('issuerPublicKey is required');
170
+ const normalizedBlinding = bytes(blindingFactor, 'blindingFactor', 32);
171
+ const numBits = rangeBits(upperBound);
172
+ const bases = deriveZkRangeBases(domain);
173
+ const engine = requireBackend(backend || await loadBulletproofBackend());
174
+ const result = await engine.batchRangeProof({
175
+ v: [BigInt(hiddenValue), BigInt(upperBound - hiddenValue)],
176
+ rs: [normalizedBlinding, negateScalar(normalizedBlinding)],
177
+ valBase: bases.valBase,
178
+ randBase: bases.randBase,
179
+ numBits,
180
+ });
181
+ if (!result || !(result.proof instanceof Uint8Array) || !Array.isArray(result.comms) || result.comms.length !== 2) throw new Error('ZK range backend returned a malformed proof');
182
+ const first = bytes(result.comms[0], 'first commitment', 32);
183
+ const second = bytes(result.comms[1], 'second commitment', 32);
184
+ if (!equalBytes(second, linkedSecondCommitment(upperBound, first, bases.valBase))) throw new Error('ZK range backend returned unlinked commitments');
185
+ const statement = publicStatement({ policyHash, actionPredicate, max: upperBound, baseReceiptDigest, issuerPublicKey, numBits });
186
+ const commitments = envelopeCommitments([first, second]);
187
+ const envelope = {
188
+ '@version': ZK_RANGE_RECEIPT_VERSION,
189
+ scheme: ZK_RANGE_SCHEME,
190
+ domain,
191
+ nonce,
192
+ statement,
193
+ commitments,
194
+ proof: b64(result.proof),
195
+ binding: `sha256:${sha256Hex(canonicalize({ statement, commitments, nonce, domain }))}`,
196
+ };
197
+ return envelope;
198
+ }
199
+
200
+ function envelopeCommitments(commitments) {
201
+ return commitments.map((value) => b64(value));
202
+ }
203
+
204
+ /** Verify the range proof and its public commitment relation. */
205
+ export async function verifyZkRangeReceipt(receipt, { backend = null } = {}) {
206
+ try {
207
+ if (!receipt || receipt['@version'] !== ZK_RANGE_RECEIPT_VERSION || receipt.scheme !== ZK_RANGE_SCHEME) return { ok: false, reason: 'malformed_zk_range_receipt' };
208
+ const statement = receipt.statement;
209
+ const max = safeU64(statement?.max, 'statement.max');
210
+ const numBits = rangeBits(max);
211
+ if (statement.num_bits !== numBits) return { ok: false, reason: 'range_bits_mismatch' };
212
+ publicStatement({
213
+ policyHash: statement.policy_hash,
214
+ actionPredicate: statement.action_predicate,
215
+ baseReceiptDigest: statement.base_receipt_digest,
216
+ issuerPublicKey: statement.issuer_public_key,
217
+ max,
218
+ numBits,
219
+ });
220
+ const bases = deriveZkRangeBases(receipt.domain);
221
+ const commitments = receipt.commitments?.map((value) => bytes(Buffer.from(value, 'base64url'), 'commitment', 32));
222
+ if (!Array.isArray(commitments) || commitments.length !== 2) return { ok: false, reason: 'commitments_malformed' };
223
+ if (!equalBytes(commitments[1], linkedSecondCommitment(max, commitments[0], bases.valBase))) return { ok: false, reason: 'commitment_relation_invalid' };
224
+ const expectedBinding = `sha256:${sha256Hex(canonicalize({ statement, commitments: envelopeCommitments(commitments), nonce: receipt.nonce, domain: receipt.domain }))}`;
225
+ if (expectedBinding !== receipt.binding) return { ok: false, reason: 'zk_binding_invalid' };
226
+ const engine = requireBackend(backend || await loadBulletproofBackend());
227
+ const valid = await engine.batchVerifyProof({
228
+ proof: bytes(Buffer.from(receipt.proof || '', 'base64url'), 'proof'),
229
+ comms: commitments,
230
+ valBase: bases.valBase,
231
+ randBase: bases.randBase,
232
+ numBits,
233
+ });
234
+ return valid === true
235
+ ? { ok: true, scheme: ZK_RANGE_SCHEME, statement }
236
+ : { ok: false, reason: 'zk_range_proof_invalid' };
237
+ } catch (error) {
238
+ return { ok: false, reason: 'zk_range_receipt_invalid', detail: (error instanceof Error && error.message) || 'invalid proof' };
239
+ }
240
+ }
241
+
242
+ export default {
243
+ ZK_RANGE_RECEIPT_VERSION,
244
+ ZK_RANGE_SCHEME,
245
+ ZK_RANGE_BACKEND_PACKAGE,
246
+ deriveZkRangeBases,
247
+ loadBulletproofBackend,
248
+ mintZkRangeReceipt,
249
+ verifyZkRangeReceipt,
250
+ };
package/store-postgres.js CHANGED
@@ -1,162 +1,4 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
- /**
3
- * EMILIA Gate — reference DURABLE consumption backend: Postgres
4
- * (EP-GATE-PG-CONSUMPTION-v2).
5
- *
6
- * Replay defense that survives restarts. This module implements the backend
7
- * contract consumed by `createDurableConsumptionStore` in ./store.js:
8
- *
9
- * backend = {
10
- * async addIfAbsent(key, value, { ttlSeconds }?) : boolean // true iff inserted
11
- * async compareAndSet(key, expected, replacement, { ttlSeconds }?) : boolean
12
- * async deleteIfValue(key, expected) : boolean
13
- * async has(key) : boolean
14
- * }
15
- *
16
- * plus a `cleanupExpired(now)` garbage-collection statement.
17
- *
18
- * Each transition is one SQL statement. `addIfAbsent` decides first use;
19
- * `compareAndSet` and `deleteIfValue` bind commit/release to the opaque owner of
20
- * the current reservation. There is no read-then-write interval in which a
21
- * delayed worker can overwrite or remove a newer worker's reservation.
22
- *
23
- * FAIL-CLOSED CONTRACT: if the injected `query` THROWS (connection down,
24
- * timeout, constraint other than the PK, ...) the error PROPAGATES to the
25
- * caller — nothing here catches it. The gate must refuse an action when
26
- * one-time-use cannot be proven; a backend error is NEVER treated as
27
- * not-consumed (which would admit replays during an outage) and never treated
28
- * as consumed-silently (which would mask the outage as a replay verdict).
29
- * Likewise, an EXPIRED row that cleanup has not yet removed still refuses:
30
- * TTL expiry is garbage collection, never a grant — the gate already rejects
31
- * stale receipts on freshness, so nothing is lost by refusing conservatively.
32
- *
33
- * Deterministic by construction: the pg-style `query(text, params)` function
34
- * and the clock (`now`) are both injected, so tests run against an in-memory
35
- * fake with real ON CONFLICT semantics — no network, no database.
36
- */
37
-
38
- export const PG_CONSUMPTION_VERSION = 'EP-GATE-PG-CONSUMPTION-v2';
39
-
40
- /** Single consumption table. Timestamps are epoch milliseconds (BIGINT) so the
41
- * injected JS clock maps 1:1 onto column values with no timezone ambiguity. */
42
- export const CONSUMPTION_TABLE = 'ep_gate_consumption';
43
-
44
- export const CONSUMPTION_TABLE_DDL = `CREATE TABLE IF NOT EXISTS ${CONSUMPTION_TABLE} (
45
- consumption_key TEXT PRIMARY KEY,
46
- state TEXT NOT NULL,
47
- consumed_at BIGINT NOT NULL,
48
- expires_at BIGINT
49
- );
50
- CREATE INDEX IF NOT EXISTS ${CONSUMPTION_TABLE}_expires_idx
51
- ON ${CONSUMPTION_TABLE} (expires_at) WHERE expires_at IS NOT NULL;`;
52
-
53
- /** The exact statements the backend issues — exported for transparency and so
54
- * a fake client can implement them without parsing SQL. */
55
- export const CONSUMPTION_SQL = {
56
- health: `SELECT
57
- to_regclass('public.${CONSUMPTION_TABLE}') IS NOT NULL AS table_ready,
58
- CASE WHEN to_regclass('public.${CONSUMPTION_TABLE}') IS NULL THEN FALSE
59
- ELSE has_table_privilege(current_user, to_regclass('public.${CONSUMPTION_TABLE}'), 'SELECT,INSERT,UPDATE,DELETE') END AS can_use`,
60
- /** $1 key, $2 state, $3 consumed_at ms, $4 expires_at ms|null. rowCount 1 = consumed, 0 = replay. */
61
- addIfAbsent: `INSERT INTO ${CONSUMPTION_TABLE} (consumption_key, state, consumed_at, expires_at) `
62
- + 'VALUES ($1, $2, $3, $4) ON CONFLICT (consumption_key) DO NOTHING',
63
- /** $1 key, $2 expected state, $3 replacement, $4 consumed_at ms, $5 expires_at ms|null. */
64
- compareAndSet: `UPDATE ${CONSUMPTION_TABLE} SET state = $3, consumed_at = $4, expires_at = $5 `
65
- + 'WHERE consumption_key = $1 AND state = $2',
66
- /** $1 key, $2 expected state. */
67
- deleteIfValue: `DELETE FROM ${CONSUMPTION_TABLE} WHERE consumption_key = $1 AND state = $2`,
68
- /** $1 key. Any row — even an expired one — counts as consumed until cleaned. */
69
- has: `SELECT 1 FROM ${CONSUMPTION_TABLE} WHERE consumption_key = $1`,
70
- /** $1 now ms. Removes ONLY rows whose TTL has elapsed; NULL expires_at never expires. */
71
- cleanupExpired: `DELETE FROM ${CONSUMPTION_TABLE} WHERE state LIKE 'committed:%' `
72
- + 'AND expires_at IS NOT NULL AND expires_at <= $1',
73
- };
74
-
75
- /**
76
- * Create the Postgres consumption backend.
77
- * @param {object} o
78
- * @param {(text: string, params: any[]) => Promise<{ rowCount: number, rows?: any[] }>} o.query
79
- * pg-style query function (e.g. `pool.query.bind(pool)`). Injected so tests
80
- * need no database. MUST throw on failure — errors propagate (fail closed).
81
- * @param {number|function} [o.now=Date.now] injected clock (ms or () => ms).
82
- * @returns backend conforming to createDurableConsumptionStore, plus cleanupExpired(now).
83
- */
84
- export function createPostgresBackend({ query, now = Date.now } = {}) {
85
- if (typeof query !== 'function') {
86
- throw new Error('createPostgresBackend: query must be an async (text, params) => { rowCount } function '
87
- + '(e.g. pg pool.query). It must THROW on failure — a backend error must never look like a verdict.');
88
- }
89
- let lastObservedNow = Number.NEGATIVE_INFINITY;
90
- const checkedNow = (candidate) => {
91
- if (!Number.isSafeInteger(candidate) || candidate < 0) {
92
- throw new Error('consumption clock must return a non-negative safe-integer epoch millisecond');
93
- }
94
- if (candidate < lastObservedNow) {
95
- throw new Error(`consumption clock regression refused: ${candidate} < ${lastObservedNow}`);
96
- }
97
- lastObservedNow = candidate;
98
- return candidate;
99
- };
100
- const nowMs = () => checkedNow(typeof now === 'function' ? now() : now);
101
- const expiryFor = (opt) => {
102
- const ttl = Number(opt?.ttlSeconds);
103
- return Number.isFinite(ttl) && ttl > 0 ? nowMs() + ttl * 1000 : null;
104
- };
105
-
106
- return {
107
- durable: true,
108
- async health() {
109
- const res = await query(CONSUMPTION_SQL.health, []);
110
- if (!res || res.rowCount !== 1 || !Array.isArray(res.rows) || res.rows.length !== 1) {
111
- throw new Error('consumption health: malformed Postgres result');
112
- }
113
- return {
114
- ok: res.rows[0].table_ready === true && res.rows[0].can_use === true,
115
- version: PG_CONSUMPTION_VERSION,
116
- };
117
- },
118
- /** True iff THIS call inserted the row — the atomic consumed-vs-replay decision. */
119
- async addIfAbsent(key, value, opt) {
120
- const res = await query(CONSUMPTION_SQL.addIfAbsent, [key, value, nowMs(), expiryFor(opt)]);
121
- // Fail closed on a malformed driver result: without a numeric rowCount we
122
- // cannot PROVE first-use, so refuse loudly rather than guess.
123
- if (!res || typeof res.rowCount !== 'number') {
124
- throw new Error('addIfAbsent: query result has no numeric rowCount — cannot prove one-time use');
125
- }
126
- return res.rowCount === 1;
127
- },
128
-
129
- /** Ownership-fenced reserved -> committed transition. */
130
- async compareAndSet(key, expected, replacement, opt) {
131
- const res = await query(CONSUMPTION_SQL.compareAndSet, [key, expected, replacement, nowMs(), expiryFor(opt)]);
132
- if (!res || typeof res.rowCount !== 'number') {
133
- throw new Error('compareAndSet: query result has no numeric rowCount — cannot prove reservation ownership');
134
- }
135
- return res.rowCount === 1;
136
- },
137
-
138
- /** Remove only the reservation owned by the caller. */
139
- async deleteIfValue(key, expected) {
140
- const res = await query(CONSUMPTION_SQL.deleteIfValue, [key, expected]);
141
- if (!res || typeof res.rowCount !== 'number') {
142
- throw new Error('deleteIfValue: query result has no numeric rowCount — cannot prove reservation ownership');
143
- }
144
- return res.rowCount === 1;
145
- },
146
-
147
- /** Present = consumed. Expired-but-uncleaned rows still count (conservative). */
148
- async has(key) {
149
- const res = await query(CONSUMPTION_SQL.has, [key]);
150
- return (res?.rows?.length ?? res?.rowCount ?? 0) > 0;
151
- },
152
-
153
- /** Garbage-collect rows whose TTL elapsed. Returns the number removed. */
154
- async cleanupExpired(at) {
155
- const cleanupAt = at === undefined ? nowMs() : checkedNow(at);
156
- const res = await query(CONSUMPTION_SQL.cleanupExpired, [cleanupAt]);
157
- return res?.rowCount ?? 0;
158
- },
159
- };
160
- }
161
-
162
- export default { createPostgresBackend, CONSUMPTION_TABLE_DDL, CONSUMPTION_TABLE, CONSUMPTION_SQL, PG_CONSUMPTION_VERSION };
2
+ // Compatibility entry point for the TypeScript store-postgres module.
3
+ export * from './dist/store-postgres.js';
4
+ export { default } from './dist/store-postgres.js';