@emilia-protocol/gate 0.11.0 → 0.14.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 (425) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +310 -0
  3. package/action-control-manifest.js +3 -268
  4. package/action-escrow-custodian.js +3 -394
  5. package/action-escrow-evidence.js +3 -858
  6. package/action-escrow-package.js +3 -1668
  7. package/action-escrow-postgres.js +3 -337
  8. package/action-escrow-state.js +3 -396
  9. package/action-escrow-verifiers.js +3 -331
  10. package/action-escrow.js +3 -2447
  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 +1003 -0
  179. package/dist/index.d.ts.map +1 -0
  180. package/dist/index.js +1737 -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/proposal-to-effect.d.ts +146 -0
  203. package/dist/proposal-to-effect.d.ts.map +1 -0
  204. package/dist/proposal-to-effect.js +427 -0
  205. package/dist/proposal-to-effect.js.map +1 -0
  206. package/dist/protocol-state.d.ts +141 -0
  207. package/dist/protocol-state.d.ts.map +1 -0
  208. package/dist/protocol-state.js +106 -0
  209. package/dist/protocol-state.js.map +1 -0
  210. package/dist/receipt-program.d.ts +59 -0
  211. package/dist/receipt-program.d.ts.map +1 -0
  212. package/dist/receipt-program.js +1053 -0
  213. package/dist/receipt-program.js.map +1 -0
  214. package/dist/reliance-kernel.d.ts +66 -0
  215. package/dist/reliance-kernel.d.ts.map +1 -0
  216. package/dist/reliance-kernel.js +103 -0
  217. package/dist/reliance-kernel.js.map +1 -0
  218. package/dist/reliance-packet.d.ts +67 -0
  219. package/dist/reliance-packet.d.ts.map +1 -0
  220. package/dist/reliance-packet.js +176 -0
  221. package/dist/reliance-packet.js.map +1 -0
  222. package/dist/remedy-program-postgres.d.ts +37 -0
  223. package/dist/remedy-program-postgres.d.ts.map +1 -0
  224. package/dist/remedy-program-postgres.js +291 -0
  225. package/dist/remedy-program-postgres.js.map +1 -0
  226. package/dist/remedy-program-receipt.d.ts +97 -0
  227. package/dist/remedy-program-receipt.d.ts.map +1 -0
  228. package/dist/remedy-program-receipt.js +817 -0
  229. package/dist/remedy-program-receipt.js.map +1 -0
  230. package/dist/remedy-program.d.ts +76 -0
  231. package/dist/remedy-program.d.ts.map +1 -0
  232. package/dist/remedy-program.js +1346 -0
  233. package/dist/remedy-program.js.map +1 -0
  234. package/dist/reports/art14.d.ts +101 -0
  235. package/dist/reports/art14.d.ts.map +1 -0
  236. package/dist/reports/art14.js +340 -0
  237. package/dist/reports/art14.js.map +1 -0
  238. package/dist/reports/assurance-package.d.ts +197 -0
  239. package/dist/reports/assurance-package.d.ts.map +1 -0
  240. package/dist/reports/assurance-package.js +313 -0
  241. package/dist/reports/assurance-package.js.map +1 -0
  242. package/dist/reports/auditor-workpaper.d.ts +194 -0
  243. package/dist/reports/auditor-workpaper.d.ts.map +1 -0
  244. package/dist/reports/auditor-workpaper.js +545 -0
  245. package/dist/reports/auditor-workpaper.js.map +1 -0
  246. package/dist/reports/external-verification.d.ts +76 -0
  247. package/dist/reports/external-verification.d.ts.map +1 -0
  248. package/dist/reports/external-verification.js +209 -0
  249. package/dist/reports/external-verification.js.map +1 -0
  250. package/dist/reports/reperform.d.ts +122 -0
  251. package/dist/reports/reperform.d.ts.map +1 -0
  252. package/dist/reports/reperform.js +432 -0
  253. package/dist/reports/reperform.js.map +1 -0
  254. package/dist/reports/underwriter.d.ts +127 -0
  255. package/dist/reports/underwriter.d.ts.map +1 -0
  256. package/dist/reports/underwriter.js +348 -0
  257. package/dist/reports/underwriter.js.map +1 -0
  258. package/dist/retention.d.ts +88 -0
  259. package/dist/retention.d.ts.map +1 -0
  260. package/dist/retention.js +90 -0
  261. package/dist/retention.js.map +1 -0
  262. package/dist/roster.d.ts +113 -0
  263. package/dist/roster.d.ts.map +1 -0
  264. package/dist/roster.js +261 -0
  265. package/dist/roster.js.map +1 -0
  266. package/dist/runtime-monitor.d.ts +132 -0
  267. package/dist/runtime-monitor.d.ts.map +1 -0
  268. package/dist/runtime-monitor.js +197 -0
  269. package/dist/runtime-monitor.js.map +1 -0
  270. package/dist/settlement.d.ts +68 -0
  271. package/dist/settlement.d.ts.map +1 -0
  272. package/dist/settlement.js +306 -0
  273. package/dist/settlement.js.map +1 -0
  274. package/dist/siem.d.ts +261 -0
  275. package/dist/siem.d.ts.map +1 -0
  276. package/dist/siem.js +247 -0
  277. package/dist/siem.js.map +1 -0
  278. package/dist/store-postgres.d.ts +107 -0
  279. package/dist/store-postgres.d.ts.map +1 -0
  280. package/dist/store-postgres.js +152 -0
  281. package/dist/store-postgres.js.map +1 -0
  282. package/dist/store.d.ts +95 -0
  283. package/dist/store.d.ts.map +1 -0
  284. package/dist/store.js +202 -0
  285. package/dist/store.js.map +1 -0
  286. package/dist/strict-json.d.ts +14 -0
  287. package/dist/strict-json.d.ts.map +1 -0
  288. package/dist/strict-json.js +132 -0
  289. package/dist/strict-json.js.map +1 -0
  290. package/dist/trust-program-adapters.d.ts +122 -0
  291. package/dist/trust-program-adapters.d.ts.map +1 -0
  292. package/dist/trust-program-adapters.js +802 -0
  293. package/dist/trust-program-adapters.js.map +1 -0
  294. package/dist/trust-program-postgres.d.ts +41 -0
  295. package/dist/trust-program-postgres.d.ts.map +1 -0
  296. package/dist/trust-program-postgres.js +346 -0
  297. package/dist/trust-program-postgres.js.map +1 -0
  298. package/dist/trust-program-revocation.d.ts +206 -0
  299. package/dist/trust-program-revocation.d.ts.map +1 -0
  300. package/dist/trust-program-revocation.js +600 -0
  301. package/dist/trust-program-revocation.js.map +1 -0
  302. package/dist/trust-program.d.ts +197 -0
  303. package/dist/trust-program.d.ts.map +1 -0
  304. package/dist/trust-program.js +1351 -0
  305. package/dist/trust-program.js.map +1 -0
  306. package/dist/witness-postgres.d.ts +43 -0
  307. package/dist/witness-postgres.d.ts.map +1 -0
  308. package/dist/witness-postgres.js +92 -0
  309. package/dist/witness-postgres.js.map +1 -0
  310. package/dist/zk-range-proof.d.ts +78 -0
  311. package/dist/zk-range-proof.d.ts.map +1 -0
  312. package/dist/zk-range-proof.js +228 -0
  313. package/dist/zk-range-proof.js.map +1 -0
  314. package/eg1-conformance.js +3 -404
  315. package/enterprise.js +3 -180
  316. package/ep-assure.mjs +1 -0
  317. package/evidence-postgres.js +3 -356
  318. package/evidence.js +4 -360
  319. package/execution-binding.js +3 -212
  320. package/formal-runtime-map.js +4 -0
  321. package/index.js +4 -1249
  322. package/key-registry.js +3 -134
  323. package/mcp.js +3 -109
  324. package/metering.js +3 -226
  325. package/metrics.js +3 -231
  326. package/network-witness.js +3 -499
  327. package/package.json +35 -4
  328. package/proposal-to-effect.js +4 -0
  329. package/receipt-program.js +4 -0
  330. package/reliance-kernel.js +3 -112
  331. package/reliance-packet.js +3 -175
  332. package/remedy-program-postgres.js +4 -0
  333. package/remedy-program-receipt.js +4 -0
  334. package/remedy-program.js +4 -0
  335. package/reports/art14.js +0 -0
  336. package/reports/assurance-package.js +2 -312
  337. package/reports/auditor-workpaper.js +3 -537
  338. package/reports/external-verification.js +3 -222
  339. package/reports/reperform.js +3 -424
  340. package/reports/underwriter.js +3 -339
  341. package/retention.js +3 -84
  342. package/roster.js +3 -264
  343. package/runtime-monitor.js +4 -0
  344. package/settlement.js +3 -299
  345. package/siem.js +3 -235
  346. package/src/action-control-manifest.ts +424 -0
  347. package/src/action-escrow-custodian.ts +427 -0
  348. package/src/action-escrow-evidence.ts +1178 -0
  349. package/src/action-escrow-package.ts +1821 -0
  350. package/src/action-escrow-postgres.ts +366 -0
  351. package/src/action-escrow-state.ts +498 -0
  352. package/src/action-escrow-verifiers.ts +484 -0
  353. package/src/action-escrow.ts +3039 -0
  354. package/src/action-packs.ts +170 -0
  355. package/src/adapters/_kit.ts +117 -0
  356. package/src/adapters/aws.ts +142 -0
  357. package/src/adapters/cloudflare.ts +78 -0
  358. package/src/adapters/gcp.ts +71 -0
  359. package/src/adapters/github.ts +110 -0
  360. package/src/adapters/jira.ts +56 -0
  361. package/src/adapters/k8s.ts +71 -0
  362. package/src/adapters/linear.ts +56 -0
  363. package/src/adapters/salesforce.ts +56 -0
  364. package/src/adapters/stripe.ts +82 -0
  365. package/src/adapters/supabase.ts +122 -0
  366. package/src/adapters/terraform.ts +60 -0
  367. package/src/adapters/vercel.ts +85 -0
  368. package/src/aec-execution.ts +354 -0
  369. package/src/breakglass.ts +647 -0
  370. package/src/capability-receipt.ts +1258 -0
  371. package/src/cf1-conformance.ts +120 -0
  372. package/src/challenge-store.ts +70 -0
  373. package/src/control-plane.ts +374 -0
  374. package/src/coverage.ts +832 -0
  375. package/src/deployment-attestation.ts +259 -0
  376. package/src/eg1-conformance.ts +471 -0
  377. package/src/enterprise.ts +195 -0
  378. package/src/evidence-postgres.ts +374 -0
  379. package/src/evidence.ts +367 -0
  380. package/src/execution-binding.ts +236 -0
  381. package/src/formal-runtime-map.ts +24 -0
  382. package/src/index.ts +2127 -0
  383. package/src/key-registry.ts +150 -0
  384. package/src/mcp.ts +120 -0
  385. package/src/metering.ts +237 -0
  386. package/src/metrics.ts +232 -0
  387. package/src/network-witness.ts +585 -0
  388. package/src/proposal-to-effect.ts +571 -0
  389. package/src/protocol-state.ts +143 -0
  390. package/src/protocol-state.typecheck.ts +94 -0
  391. package/src/receipt-program.ts +1105 -0
  392. package/src/reliance-kernel.ts +119 -0
  393. package/src/reliance-packet.ts +206 -0
  394. package/src/remedy-program-postgres.ts +367 -0
  395. package/src/remedy-program-receipt.ts +891 -0
  396. package/src/remedy-program.ts +1388 -0
  397. package/src/reports/art14.ts +361 -0
  398. package/src/reports/assurance-package.ts +330 -0
  399. package/src/reports/auditor-workpaper.ts +558 -0
  400. package/src/reports/external-verification.ts +232 -0
  401. package/src/reports/reperform.ts +441 -0
  402. package/src/reports/underwriter.ts +356 -0
  403. package/src/retention.ts +100 -0
  404. package/src/roster.ts +273 -0
  405. package/src/runtime-monitor.ts +217 -0
  406. package/src/settlement.ts +313 -0
  407. package/src/siem.ts +247 -0
  408. package/src/store-postgres.ts +167 -0
  409. package/src/store.ts +214 -0
  410. package/src/strict-json.ts +115 -0
  411. package/src/trust-program-adapters.ts +847 -0
  412. package/src/trust-program-postgres.ts +429 -0
  413. package/src/trust-program-revocation.ts +751 -0
  414. package/src/trust-program.ts +1460 -0
  415. package/src/witness-postgres.ts +106 -0
  416. package/src/zk-range-proof.ts +250 -0
  417. package/store-postgres.js +3 -161
  418. package/store.js +4 -198
  419. package/strict-json.js +3 -102
  420. package/trust-program-adapters.js +4 -0
  421. package/trust-program-postgres.js +4 -0
  422. package/trust-program-revocation.js +4 -0
  423. package/trust-program.js +4 -0
  424. package/witness-postgres.js +3 -96
  425. package/zk-range-proof.js +4 -0
@@ -0,0 +1,571 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Proposal-to-Effect is a product orchestration profile over existing EMILIA
4
+ * artifacts. A proposal is deliberately NOT a bearer authorization object.
5
+ * Authority remains in EP-RECEIPT-v1 and the relying party's pinned AEB
6
+ * requirement; consequence custody remains in Gate and its durable stores.
7
+ */
8
+
9
+ import {
10
+ beginReceiptApproval,
11
+ pollReceiptApproval,
12
+ approvalActionHash,
13
+ EP_APPROVAL_FLOW,
14
+ validateApprovalAuthorization,
15
+ validateCaidSelector,
16
+ validateRequiredFields,
17
+ } from '@emilia-protocol/require-receipt/acquisition';
18
+ import {
19
+ aebReservationKey,
20
+ authorizeAebExecutionDurable,
21
+ digestAeb,
22
+ pinnedConfigDigest,
23
+ reconcileAebExecutionDurable,
24
+ verifyAebEvaluation,
25
+ type AebAdapter,
26
+ type AebDigest,
27
+ type AebDurableConsumptionStore,
28
+ type AebEvaluationRecord,
29
+ type AebPinnedConfig,
30
+ } from '@emilia-protocol/verify/aeb-adapter-contract';
31
+ import { actionDigest as aecActionDigest } from '@emilia-protocol/verify/evidence-chain';
32
+
33
+ export const PROPOSAL_TO_EFFECT_VERSION = 'EMILIA-PROPOSAL-TO-EFFECT-v1';
34
+
35
+ type JsonObject = Record<string, any>;
36
+ type FetchLike = typeof fetch;
37
+
38
+ const CAID_PATTERN = /^caid:1:[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)*\.[1-9][0-9]*:[a-z0-9]+(?:-[a-z0-9]+)*:[A-Za-z0-9_-]{43}$/;
39
+ const IDENTIFIER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9:_.@/-]{2,255}$/;
40
+
41
+ export interface ProposalToEffectProfile {
42
+ id: string;
43
+ action_type: string;
44
+ selector: JsonObject;
45
+ required_fields: readonly string[];
46
+ authorization: {
47
+ authorization_endpoint: string;
48
+ flow: typeof EP_APPROVAL_FLOW;
49
+ };
50
+ aeb_requirement_ref: string;
51
+ ttl_sec: number;
52
+ /**
53
+ * Relying-party-controlled canonicalization and CAID derivation. It runs on
54
+ * both proposal creation and execution. Never select it from presented data.
55
+ */
56
+ canonicalize_action(input: unknown): { action: JsonObject; caid: string };
57
+ caid_selector?: { field: string };
58
+ }
59
+
60
+ export interface ProposalToEffectProposal {
61
+ '@version': typeof PROPOSAL_TO_EFFECT_VERSION;
62
+ proposal_id: string;
63
+ operation_id: string;
64
+ initiator_id: string;
65
+ profile_id: string;
66
+ action: JsonObject;
67
+ action_digest: string;
68
+ aeb_action_digest: AebDigest;
69
+ caid: string;
70
+ created_at: string;
71
+ expires_at: string;
72
+ challenge: {
73
+ action: string;
74
+ action_hash: string;
75
+ required_fields: string[];
76
+ caid_selector?: { field: string };
77
+ };
78
+ authorization: {
79
+ authorization_endpoint: string;
80
+ flow: typeof EP_APPROVAL_FLOW;
81
+ };
82
+ aeb: {
83
+ requirement_ref: string;
84
+ pinned_config_digest: AebDigest;
85
+ consumption_nonce: AebDigest;
86
+ };
87
+ }
88
+
89
+ export interface ProposalToEffectGate {
90
+ check(input: JsonObject): Promise<JsonObject>;
91
+ run(input: JsonObject, effect: (authorization: JsonObject) => unknown | Promise<unknown>): Promise<JsonObject>;
92
+ }
93
+
94
+ export interface ProposalToEffectProviderVerification {
95
+ valid: boolean;
96
+ outcome?: 'COMMITTED' | 'NOT_COMMITTED';
97
+ evidence_digest?: AebDigest | null;
98
+ reason?: string;
99
+ }
100
+
101
+ export interface ProposalToEffectOptions {
102
+ gate: ProposalToEffectGate;
103
+ profiles: Record<string, ProposalToEffectProfile>;
104
+ aeb: {
105
+ config: AebPinnedConfig;
106
+ adapters: Record<string, AebAdapter>;
107
+ store: AebDurableConsumptionStore;
108
+ resolve_artifacts(input: {
109
+ proposal: ProposalToEffectProposal;
110
+ evaluation: AebEvaluationRecord;
111
+ }): Promise<Record<string, unknown>> | Record<string, unknown>;
112
+ verify_provider_evidence(input: {
113
+ evidence: unknown;
114
+ expected: {
115
+ operation_id: string;
116
+ caid: string;
117
+ action_digest: AebDigest;
118
+ };
119
+ }): Promise<ProposalToEffectProviderVerification> | ProposalToEffectProviderVerification;
120
+ };
121
+ now?: () => number;
122
+ }
123
+
124
+ function isPlainObject(value: unknown): value is JsonObject {
125
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
126
+ const prototype = Object.getPrototypeOf(value);
127
+ return prototype === Object.prototype || prototype === null;
128
+ }
129
+
130
+ function clone<T>(value: T): T {
131
+ return structuredClone(value);
132
+ }
133
+
134
+ function assertIdentifier(value: unknown, name: string): asserts value is string {
135
+ if (typeof value !== 'string' || !IDENTIFIER_PATTERN.test(value)) {
136
+ throw new Error(`${name}_invalid`);
137
+ }
138
+ }
139
+
140
+ function assertProfile(profile: ProposalToEffectProfile): void {
141
+ if (!isPlainObject(profile)) throw new Error('proposal_profile_invalid');
142
+ assertIdentifier(profile.id, 'proposal_profile_id');
143
+ assertIdentifier(profile.action_type, 'proposal_action_type');
144
+ assertIdentifier(profile.aeb_requirement_ref, 'proposal_aeb_requirement_ref');
145
+ if (!isPlainObject(profile.selector) || Object.keys(profile.selector).length === 0) {
146
+ throw new Error('proposal_selector_invalid');
147
+ }
148
+ const requiredFields = validateRequiredFields(profile.required_fields);
149
+ if (!requiredFields.ok) throw new Error(requiredFields.reason);
150
+ if (!Number.isSafeInteger(profile.ttl_sec) || profile.ttl_sec <= 0 || profile.ttl_sec > 86_400) {
151
+ throw new Error('proposal_ttl_invalid');
152
+ }
153
+ if (typeof profile.canonicalize_action !== 'function') {
154
+ throw new Error('proposal_canonicalizer_required');
155
+ }
156
+ const authorization = validateApprovalAuthorization(profile.authorization);
157
+ if (!authorization.ok) throw new Error(authorization.reason);
158
+ if (profile.caid_selector) {
159
+ const caidSelector = validateCaidSelector(profile.caid_selector);
160
+ if (!caidSelector.ok) throw new Error(caidSelector.reason);
161
+ }
162
+ }
163
+
164
+ function canonicalizeForProfile(profile: ProposalToEffectProfile, input: unknown): { action: JsonObject; caid: string } {
165
+ const normalized = profile.canonicalize_action(clone(input));
166
+ if (!isPlainObject(normalized) || !isPlainObject(normalized.action)
167
+ || typeof normalized.caid !== 'string' || !CAID_PATTERN.test(normalized.caid)) {
168
+ throw new Error('proposal_canonicalization_invalid');
169
+ }
170
+ if (normalized.action.action_type !== profile.action_type) {
171
+ throw new Error('proposal_action_type_mismatch');
172
+ }
173
+ for (const field of profile.required_fields) {
174
+ if (!Object.hasOwn(normalized.action, field) || normalized.action[field] === undefined) {
175
+ throw new Error(`proposal_required_field_missing:${field}`);
176
+ }
177
+ }
178
+ if (profile.caid_selector) {
179
+ const field = profile.caid_selector.field;
180
+ if (typeof field !== 'string' || normalized.action[field] !== normalized.caid) {
181
+ throw new Error(`proposal_caid_binding_invalid:${field}`);
182
+ }
183
+ }
184
+ // Both digest functions reject unsupported/non-canonical JSON values.
185
+ approvalActionHash(normalized.action);
186
+ digestAeb(normalized.action);
187
+ return { action: clone(normalized.action), caid: normalized.caid };
188
+ }
189
+
190
+ function assertSameObject(left: unknown, right: unknown, reason: string): void {
191
+ if (digestAeb(left) !== digestAeb(right)) throw new Error(reason);
192
+ }
193
+
194
+ function exactProposalKeys(proposal: JsonObject): boolean {
195
+ const expected = [
196
+ '@version', 'action', 'action_digest', 'aeb', 'aeb_action_digest', 'authorization',
197
+ 'caid', 'challenge', 'created_at', 'expires_at', 'initiator_id', 'operation_id',
198
+ 'profile_id', 'proposal_id',
199
+ ].sort();
200
+ const actual = Object.keys(proposal).sort();
201
+ return expected.length === actual.length && expected.every((key, index) => key === actual[index]);
202
+ }
203
+
204
+ function proposalAdmissibility(proposal: ProposalToEffectProposal, record: AebEvaluationRecord): JsonObject {
205
+ return {
206
+ admissibility_profile: { id: `aeb:${proposal.aeb.requirement_ref}`, version: '1' },
207
+ profile_hash: proposal.aeb.pinned_config_digest,
208
+ verdict: 'admissible',
209
+ replay_digest: record.evidence_digest,
210
+ challenge_id: proposal.proposal_id,
211
+ aeb_evaluation_digest: digestAeb(record),
212
+ };
213
+ }
214
+
215
+ function refusal(reason: string, extra: JsonObject = {}): JsonObject {
216
+ return { ok: false, reason, ...extra };
217
+ }
218
+
219
+ export function proposalToEffectConsumptionNonce(
220
+ operationId: string,
221
+ pinnedConfigDigest: AebDigest,
222
+ ): AebDigest {
223
+ assertIdentifier(operationId, 'proposal_operation_id');
224
+ if (typeof pinnedConfigDigest !== 'string' || !/^sha256:[a-f0-9]{64}$/.test(pinnedConfigDigest)) {
225
+ throw new Error('proposal_aeb_pin_invalid');
226
+ }
227
+ return digestAeb({
228
+ domain: PROPOSAL_TO_EFFECT_VERSION,
229
+ operation_id: operationId,
230
+ pinned_config_digest: pinnedConfigDigest,
231
+ });
232
+ }
233
+
234
+ function expectedAebCompositionDigest(proposal: ProposalToEffectProposal): AebDigest {
235
+ return `sha256:${aecActionDigest({
236
+ caid: proposal.caid,
237
+ normalized_action_digest: proposal.aeb_action_digest,
238
+ })}` as AebDigest;
239
+ }
240
+
241
+ export function createProposalToEffect(options: ProposalToEffectOptions) {
242
+ if (!options?.gate || typeof options.gate.check !== 'function' || typeof options.gate.run !== 'function') {
243
+ throw new Error('proposal_gate_required');
244
+ }
245
+ if (!isPlainObject(options.profiles) || Object.keys(options.profiles).length === 0) {
246
+ throw new Error('proposal_profiles_required');
247
+ }
248
+ for (const [id, profile] of Object.entries(options.profiles)) {
249
+ assertProfile(profile);
250
+ if (id !== profile.id) throw new Error('proposal_profile_registry_mismatch');
251
+ }
252
+ if (!options.aeb?.config || !options.aeb.adapters || !options.aeb.store
253
+ || typeof options.aeb.resolve_artifacts !== 'function'
254
+ || typeof options.aeb.verify_provider_evidence !== 'function') {
255
+ throw new Error('proposal_aeb_configuration_required');
256
+ }
257
+ const now = options.now ?? Date.now;
258
+ const configDigest = pinnedConfigDigest(options.aeb.config);
259
+
260
+ function profileFor(id: unknown): ProposalToEffectProfile {
261
+ if (typeof id !== 'string' || !options.profiles[id]) throw new Error('proposal_profile_not_pinned');
262
+ return options.profiles[id];
263
+ }
264
+
265
+ function prepare(input: {
266
+ proposal_id: string;
267
+ profile_id: string;
268
+ operation_id: string;
269
+ initiator_id: string;
270
+ action: unknown;
271
+ }): ProposalToEffectProposal {
272
+ assertIdentifier(input?.proposal_id, 'proposal_id');
273
+ assertIdentifier(input?.operation_id, 'proposal_operation_id');
274
+ assertIdentifier(input?.initiator_id, 'proposal_initiator_id');
275
+ const profile = profileFor(input?.profile_id);
276
+ const normalized = canonicalizeForProfile(profile, input.action);
277
+ const createdAtMs = now();
278
+ if (!Number.isFinite(createdAtMs)) throw new Error('proposal_time_invalid');
279
+ const actionDigest = approvalActionHash(normalized.action);
280
+ return clone({
281
+ '@version': PROPOSAL_TO_EFFECT_VERSION,
282
+ proposal_id: input.proposal_id,
283
+ operation_id: input.operation_id,
284
+ initiator_id: input.initiator_id,
285
+ profile_id: profile.id,
286
+ action: normalized.action,
287
+ action_digest: actionDigest,
288
+ aeb_action_digest: digestAeb(normalized.action),
289
+ caid: normalized.caid,
290
+ created_at: new Date(createdAtMs).toISOString(),
291
+ expires_at: new Date(createdAtMs + profile.ttl_sec * 1000).toISOString(),
292
+ challenge: {
293
+ action: profile.action_type,
294
+ action_hash: actionDigest,
295
+ required_fields: [...profile.required_fields],
296
+ ...(profile.caid_selector ? { caid_selector: clone(profile.caid_selector) } : {}),
297
+ },
298
+ authorization: clone(profile.authorization),
299
+ aeb: {
300
+ requirement_ref: profile.aeb_requirement_ref,
301
+ pinned_config_digest: configDigest,
302
+ consumption_nonce: proposalToEffectConsumptionNonce(input.operation_id, configDigest),
303
+ },
304
+ });
305
+ }
306
+
307
+ function verifyProposal(input: unknown, { allowExpired = false }: { allowExpired?: boolean } = {}): {
308
+ proposal: ProposalToEffectProposal;
309
+ profile: ProposalToEffectProfile;
310
+ } {
311
+ if (!isPlainObject(input) || !exactProposalKeys(input)
312
+ || input['@version'] !== PROPOSAL_TO_EFFECT_VERSION) {
313
+ throw new Error('proposal_shape_invalid');
314
+ }
315
+ const proposal = input as ProposalToEffectProposal;
316
+ assertIdentifier(proposal.proposal_id, 'proposal_id');
317
+ assertIdentifier(proposal.operation_id, 'proposal_operation_id');
318
+ assertIdentifier(proposal.initiator_id, 'proposal_initiator_id');
319
+ const profile = profileFor(proposal.profile_id);
320
+ const normalized = canonicalizeForProfile(profile, proposal.action);
321
+ if (normalized.caid !== proposal.caid) throw new Error('proposal_caid_mismatch');
322
+ assertSameObject(normalized.action, proposal.action, 'proposal_action_not_canonical');
323
+ if (approvalActionHash(normalized.action) !== proposal.action_digest) {
324
+ throw new Error('proposal_action_digest_mismatch');
325
+ }
326
+ if (digestAeb(normalized.action) !== proposal.aeb_action_digest) {
327
+ throw new Error('proposal_aeb_action_digest_mismatch');
328
+ }
329
+ if (!Number.isFinite(Date.parse(proposal.created_at)) || !Number.isFinite(Date.parse(proposal.expires_at))
330
+ || Date.parse(proposal.expires_at) <= Date.parse(proposal.created_at)) {
331
+ throw new Error('proposal_time_invalid');
332
+ }
333
+ if (!allowExpired && now() >= Date.parse(proposal.expires_at)) throw new Error('proposal_expired');
334
+ assertSameObject(proposal.authorization, profile.authorization, 'proposal_authorization_mismatch');
335
+ if (!isPlainObject(proposal.aeb)
336
+ || Object.keys(proposal.aeb).sort().join(',') !== 'consumption_nonce,pinned_config_digest,requirement_ref'
337
+ || proposal.aeb?.requirement_ref !== profile.aeb_requirement_ref
338
+ || proposal.aeb?.pinned_config_digest !== configDigest) {
339
+ throw new Error('proposal_aeb_pin_mismatch');
340
+ }
341
+ if (proposal.aeb.consumption_nonce !== proposalToEffectConsumptionNonce(proposal.operation_id, configDigest)) {
342
+ throw new Error('proposal_aeb_nonce_mismatch');
343
+ }
344
+ const expectedChallenge = {
345
+ action: profile.action_type,
346
+ action_hash: proposal.action_digest,
347
+ required_fields: [...profile.required_fields],
348
+ ...(profile.caid_selector ? { caid_selector: clone(profile.caid_selector) } : {}),
349
+ };
350
+ assertSameObject(proposal.challenge, expectedChallenge, 'proposal_challenge_mismatch');
351
+ return { proposal: clone(proposal), profile };
352
+ }
353
+
354
+ async function verifyEvaluation(proposal: ProposalToEffectProposal, evaluation: unknown) {
355
+ if (!isPlainObject(evaluation)) return { valid: false, reason: 'aeb_evaluation_missing', record: null };
356
+ const record = evaluation as unknown as AebEvaluationRecord;
357
+ if (record.operation_id !== proposal.operation_id
358
+ || record.consumption_nonce !== proposal.aeb.consumption_nonce
359
+ || record.initiator_id !== proposal.initiator_id
360
+ || record.requirement_ref !== proposal.aeb.requirement_ref
361
+ || record.caid !== proposal.caid) {
362
+ return { valid: false, reason: 'aeb_evaluation_binding_mismatch', record };
363
+ }
364
+ let artifacts: Record<string, unknown>;
365
+ try {
366
+ artifacts = await options.aeb.resolve_artifacts({ proposal: clone(proposal), evaluation: clone(record) });
367
+ } catch {
368
+ return { valid: false, reason: 'aeb_artifact_resolution_failed', record };
369
+ }
370
+ const checked = verifyAebEvaluation(record, {
371
+ config: options.aeb.config,
372
+ adapters: options.aeb.adapters,
373
+ artifacts,
374
+ now: new Date(now()).toISOString(),
375
+ });
376
+ if (!checked.valid || record.verdict !== 'SATISFIED'
377
+ || record.authority_constraints?.one_time_consumption !== true) {
378
+ return { valid: false, reason: 'aeb_evaluation_refused', record, checked };
379
+ }
380
+ if (record.composition?.action_digest !== expectedAebCompositionDigest(proposal)) {
381
+ return { valid: false, reason: 'aeb_evaluation_binding_mismatch', record, checked };
382
+ }
383
+ return { valid: true, reason: null, record, checked };
384
+ }
385
+
386
+ function gateInput(proposal: ProposalToEffectProposal, profile: ProposalToEffectProfile, receipt: unknown, record: AebEvaluationRecord) {
387
+ return {
388
+ selector: {
389
+ ...clone(profile.selector),
390
+ operation_id: proposal.operation_id,
391
+ initiator_id: proposal.initiator_id,
392
+ aeb_requirement_ref: proposal.aeb.requirement_ref,
393
+ },
394
+ receipt,
395
+ observedAction: clone(proposal.action),
396
+ admissibility: proposalAdmissibility(proposal, record),
397
+ };
398
+ }
399
+
400
+ async function execute(
401
+ input: { proposal: unknown; receipt: unknown; evaluation: unknown },
402
+ effect: (input: { action: JsonObject; proposal: ProposalToEffectProposal; authorization: JsonObject }) => unknown | Promise<unknown>,
403
+ ): Promise<JsonObject> {
404
+ if (typeof effect !== 'function') throw new Error('proposal_effect_required');
405
+ const { proposal, profile } = verifyProposal(input?.proposal);
406
+ const evaluation = await verifyEvaluation(proposal, input?.evaluation);
407
+ if (!evaluation.valid || !evaluation.record) {
408
+ return refusal(evaluation.reason || 'aeb_evaluation_refused', { aeb: evaluation.checked ?? null });
409
+ }
410
+ const preparedGateInput = gateInput(proposal, profile, input.receipt, evaluation.record);
411
+ const preflight = await options.gate.check({ ...preparedGateInput, consumptionMode: 'none' });
412
+ if (preflight.allow !== true) {
413
+ return refusal(preflight.reason || 'gate_refused', { authorization: preflight });
414
+ }
415
+ if (preflight.reason === 'not_guarded' || preflight.requirement?.receipt_required !== true) {
416
+ return refusal('gate_profile_not_receipt_guarded', { authorization: preflight });
417
+ }
418
+ const reservation = await authorizeAebExecutionDurable(evaluation.record, {
419
+ verified: true,
420
+ local_authorization: true,
421
+ store: options.aeb.store,
422
+ });
423
+ if (!reservation.invoke_allowed || !reservation.reservation_key) {
424
+ return refusal(
425
+ reservation.reason === 'consumption_conflict' ? 'aeb_consumption_conflict' : reservation.reason,
426
+ { aeb: reservation },
427
+ );
428
+ }
429
+ const key = reservation.reservation_key;
430
+ try {
431
+ const result = await options.gate.run(preparedGateInput, async (authorization) => effect({
432
+ action: clone(proposal.action),
433
+ proposal: clone(proposal),
434
+ authorization: clone(authorization),
435
+ }));
436
+ if (result?.ok !== true) {
437
+ await options.aeb.store.release(key);
438
+ return refusal(result?.authorization?.reason || result?.reason || 'gate_refused', {
439
+ authorization: result?.authorization ?? null,
440
+ });
441
+ }
442
+ const committed = await reconcileAebExecutionDurable(options.aeb.store, key, 'COMMITTED');
443
+ if (committed.state !== 'CONSUMED') {
444
+ const error: any = new Error('aeb_consumption_commit_failed');
445
+ error.code = 'EMILIA_PROPOSAL_TO_EFFECT_COMMIT_FAILED';
446
+ error.proposalToEffect = { outcome: 'executed', reservation_key: key };
447
+ throw error;
448
+ }
449
+ return { ...result, proposal: clone(proposal), aeb: committed };
450
+ } catch (error: any) {
451
+ const outcome = error?.proposalToEffect?.outcome ?? error?.emiliaGateOutcome?.outcome;
452
+ if (outcome === 'executed') {
453
+ await reconcileAebExecutionDurable(options.aeb.store, key, 'COMMITTED');
454
+ } else if (outcome !== 'indeterminate') {
455
+ await options.aeb.store.release(key);
456
+ }
457
+ throw error;
458
+ }
459
+ }
460
+
461
+ async function reconcile(input: {
462
+ proposal: unknown;
463
+ evaluation: unknown;
464
+ provider_evidence: unknown;
465
+ }): Promise<JsonObject> {
466
+ const { proposal } = verifyProposal(input?.proposal, { allowExpired: true });
467
+ if (!isPlainObject(input?.evaluation)) return refusal('aeb_evaluation_missing');
468
+ const record = input.evaluation as unknown as AebEvaluationRecord;
469
+ if (record.operation_id !== proposal.operation_id
470
+ || record.consumption_nonce !== proposal.aeb.consumption_nonce
471
+ || record.initiator_id !== proposal.initiator_id
472
+ || record.requirement_ref !== proposal.aeb.requirement_ref
473
+ || record.caid !== proposal.caid) {
474
+ return refusal('aeb_evaluation_binding_mismatch');
475
+ }
476
+ const artifacts = await options.aeb.resolve_artifacts({ proposal: clone(proposal), evaluation: clone(record) });
477
+ const historical = verifyAebEvaluation(record, {
478
+ config: options.aeb.config,
479
+ adapters: options.aeb.adapters,
480
+ artifacts,
481
+ now: record.evaluated_at,
482
+ });
483
+ if (!historical.valid) return refusal('aeb_evaluation_refused', { aeb: historical });
484
+ if (record.verdict !== 'SATISFIED'
485
+ || record.authority_constraints?.one_time_consumption !== true) {
486
+ return refusal('aeb_evaluation_refused', { aeb: historical });
487
+ }
488
+ if (record.composition?.action_digest !== expectedAebCompositionDigest(proposal)) {
489
+ return refusal('aeb_evaluation_binding_mismatch');
490
+ }
491
+ let provider: ProposalToEffectProviderVerification;
492
+ try {
493
+ provider = await options.aeb.verify_provider_evidence({
494
+ evidence: clone(input.provider_evidence),
495
+ expected: {
496
+ operation_id: proposal.operation_id,
497
+ caid: proposal.caid,
498
+ action_digest: proposal.aeb_action_digest,
499
+ },
500
+ });
501
+ } catch {
502
+ return refusal('provider_evidence_unverified');
503
+ }
504
+ if (!provider?.valid || (provider.outcome !== 'COMMITTED' && provider.outcome !== 'NOT_COMMITTED')) {
505
+ return refusal(provider?.reason || 'provider_evidence_unverified');
506
+ }
507
+ const key = aebReservationKey(record);
508
+ const reconciled = await reconcileAebExecutionDurable(options.aeb.store, key, provider.outcome);
509
+ if (reconciled.state === 'RECONCILIATION_REQUIRED') {
510
+ return refusal(reconciled.reason, { state: reconciled.state });
511
+ }
512
+ return {
513
+ ok: true,
514
+ state: reconciled.state,
515
+ outcome: provider.outcome,
516
+ evidence_digest: provider.evidence_digest ?? null,
517
+ reservation_key: key,
518
+ };
519
+ }
520
+
521
+ async function beginApproval(input: {
522
+ proposal: unknown;
523
+ approver_id: string;
524
+ idempotency_key: string;
525
+ requester_authorization: string | (() => string | Promise<string>);
526
+ fetch_impl?: FetchLike;
527
+ }): Promise<JsonObject> {
528
+ const { proposal, profile } = verifyProposal(input?.proposal);
529
+ return beginReceiptApproval({
530
+ authorization: proposal.authorization,
531
+ trustedAuthorization: profile.authorization,
532
+ challenge: proposal.challenge,
533
+ action: proposal.action,
534
+ approver_id: input.approver_id,
535
+ idempotency_key: input.idempotency_key,
536
+ requesterAuthorization: input.requester_authorization,
537
+ fetchImpl: input.fetch_impl,
538
+ });
539
+ }
540
+
541
+ async function pollApproval(input: {
542
+ proposal: unknown;
543
+ request_id: string;
544
+ poll_token: string;
545
+ fetch_impl?: FetchLike;
546
+ }): Promise<JsonObject> {
547
+ const { proposal, profile } = verifyProposal(input?.proposal, { allowExpired: true });
548
+ return pollReceiptApproval({
549
+ authorization: proposal.authorization,
550
+ trustedAuthorization: profile.authorization,
551
+ request_id: input.request_id,
552
+ poll_token: input.poll_token,
553
+ fetchImpl: input.fetch_impl,
554
+ });
555
+ }
556
+
557
+ return Object.freeze({
558
+ prepare,
559
+ verifyProposal,
560
+ beginApproval,
561
+ pollApproval,
562
+ execute,
563
+ reconcile,
564
+ });
565
+ }
566
+
567
+ export default {
568
+ PROPOSAL_TO_EFFECT_VERSION,
569
+ proposalToEffectConsumptionNonce,
570
+ createProposalToEffect,
571
+ };