@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,427 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Typed bridge between the Action Escrow kernel and an authenticated external
4
+ * custodian adapter. Provider observations are signed by the deployment
5
+ * operator because TLS API responses are not portable offline evidence.
6
+ */
7
+ import crypto from 'node:crypto';
8
+ import { canonicalize, hashCanonical } from './execution-binding.js';
9
+ import {
10
+ ACTION_ESCROW_CONTRACTOR_TEMPLATE_VERSION,
11
+ validateActionEscrowReleaseTemplate,
12
+ } from './action-escrow-verifiers.js';
13
+
14
+ export const ACTION_ESCROW_CUSTODIAN_OBSERVATION_VERSION =
15
+ 'EP-ACTION-ESCROW-CUSTODIAN-OBSERVATION-v1';
16
+ const DOMAIN = `${ACTION_ESCROW_CUSTODIAN_OBSERVATION_VERSION}\0`;
17
+ const HASH = /^sha256:[0-9a-f]{64}$/;
18
+
19
+ function isRecord(value): value is Record<string, any> {
20
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;
21
+ const prototype = Object.getPrototypeOf(value);
22
+ return prototype === Object.prototype || prototype === null;
23
+ }
24
+
25
+ function canonicalCopy(value) {
26
+ return JSON.parse(canonicalize(value));
27
+ }
28
+
29
+ function canonicalDigest(value) {
30
+ return `sha256:${hashCanonical(value)}`;
31
+ }
32
+
33
+ function validString(value, max = 512) {
34
+ return typeof value === 'string'
35
+ && value.length > 0
36
+ && value.length <= max
37
+ && !/[\u0000-\u001f\u007f]/.test(value);
38
+ }
39
+
40
+ function strictInstant(value) {
41
+ if (typeof value !== 'string') return false;
42
+ const parsed = Date.parse(value);
43
+ return Number.isFinite(parsed) && new Date(parsed).toISOString() === value;
44
+ }
45
+
46
+ function deepFreeze(value) {
47
+ if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
48
+ Object.freeze(value);
49
+ for (const child of Object.values(value)) deepFreeze(child);
50
+ return value;
51
+ }
52
+
53
+ function signingBytes(payload) {
54
+ return Buffer.concat([
55
+ Buffer.from(DOMAIN, 'utf8'),
56
+ Buffer.from(canonicalize(payload), 'utf8'),
57
+ ]);
58
+ }
59
+
60
+ function requestScope(request) {
61
+ const { request_digest: _digest, ...scope } = request;
62
+ // The digest identifies the reserved mutation. GET is only a reconciliation
63
+ // transport for that same POST and must not create a second request identity.
64
+ return { ...scope, method: 'POST' };
65
+ }
66
+
67
+ function normalizeKernelRequest(value, adapter) {
68
+ try {
69
+ if (!isRecord(value)
70
+ || (value.method !== 'POST' && value.method !== 'GET')
71
+ || value.provider_id !== adapter.provider
72
+ || value.profile?.provider_id !== adapter.provider
73
+ || !HASH.test(value.agreement_digest)
74
+ || !HASH.test(value.document_action_binding_digest)
75
+ || !HASH.test(value.release_action_digest)
76
+ || !HASH.test(value.parties_digest)
77
+ || !HASH.test(value.profile_digest)
78
+ || !HASH.test(value.document_digest)
79
+ || !HASH.test(value.request_digest)
80
+ || !validString(value.milestone_id, 256)
81
+ || !validString(value.idempotency_key, 256)
82
+ || !isRecord(value.release_action_template)) {
83
+ return null;
84
+ }
85
+ // `validateActionEscrowReleaseTemplate` (action-escrow-verifiers.ts,
86
+ // outside this file's scope) still infers its options parameter type
87
+ // from only the one destructured property that carries a default value,
88
+ // so a fresh object literal here trips the excess-property check.
89
+ // Routing through a locally typed variable avoids that without changing
90
+ // what gets passed at runtime.
91
+ const releaseTemplateOptions: {
92
+ profileDigest?: any;
93
+ agreementId?: any;
94
+ agreementDigest?: any;
95
+ milestoneId?: any;
96
+ documentDigest?: any;
97
+ contractorProjectSource?: boolean;
98
+ } = {
99
+ profileDigest: value.profile_digest,
100
+ agreementId: value.agreement_id,
101
+ agreementDigest: value.agreement_digest,
102
+ milestoneId: value.milestone_id,
103
+ documentDigest: value.document_digest,
104
+ contractorProjectSource:
105
+ value.release_action_template.action_escrow_template_profile
106
+ === ACTION_ESCROW_CONTRACTOR_TEMPLATE_VERSION,
107
+ };
108
+ const template = validateActionEscrowReleaseTemplate(
109
+ value.release_action_template,
110
+ releaseTemplateOptions,
111
+ );
112
+ if (!template
113
+ || template.custodian_provider !== adapter.provider
114
+ || template.custodian_environment !== adapter.environment
115
+ || canonicalDigest({
116
+ '@version': 'EP-ACTION-ESCROW-PROVIDER-REQUEST-v1',
117
+ ...requestScope(value),
118
+ }) !== value.request_digest) {
119
+ return null;
120
+ }
121
+ return canonicalCopy(value);
122
+ } catch {
123
+ return null;
124
+ }
125
+ }
126
+
127
+ function transactionMatches(transaction, request) {
128
+ if (!isRecord(transaction)
129
+ || transaction.transaction_id
130
+ !== request.release_action_template.custodian_transaction_id
131
+ || transaction.currency !== request.release_action_template.currency
132
+ || !Array.isArray(transaction.milestones)) {
133
+ return false;
134
+ }
135
+ const milestone = transaction.milestones.find(
136
+ (entry) => entry.provider_item_id
137
+ === request.release_action_template.custodian_milestone_id,
138
+ );
139
+ if (!milestone || !Array.isArray(milestone.schedules) || milestone.schedules.length !== 1) {
140
+ return false;
141
+ }
142
+ const schedule = milestone.schedules[0];
143
+ return schedule.amount === request.release_action_template.amount
144
+ && schedule.beneficiary_customer === request.release_action_template.destination_id;
145
+ }
146
+
147
+ function providerResultMatches(result, request, adapter, operation) {
148
+ return isRecord(result)
149
+ && result.provider === adapter.provider
150
+ && result.environment === adapter.environment
151
+ && result.operation === operation
152
+ && result.transaction_id
153
+ === request.release_action_template.custodian_transaction_id
154
+ && (operation === 'reconcile_transaction'
155
+ || (
156
+ result.milestone_id
157
+ === request.release_action_template.custodian_milestone_id
158
+ && result.effect_reference === request.idempotency_key
159
+ ));
160
+ }
161
+
162
+ function transactionFromResult(result) {
163
+ return isRecord(result?.transaction) ? result.transaction : null;
164
+ }
165
+
166
+ function observationStatus(result) {
167
+ if (result.kind === 'released') return 'released';
168
+ if (result.kind !== 'provider_action_required') return null;
169
+ if (result.provider_phase === 'not_accepted') return 'not_released';
170
+ if (result.provider_phase === 'accepted_pending_disbursement') return 'pending';
171
+ return null;
172
+ }
173
+
174
+ function normalizePrivateKey(value) {
175
+ const key = value instanceof crypto.KeyObject ? value : crypto.createPrivateKey(value);
176
+ if (key.asymmetricKeyType !== 'ed25519') {
177
+ throw new TypeError('custodian observation signer must use Ed25519');
178
+ }
179
+ return key;
180
+ }
181
+
182
+ /**
183
+ * The bridge implements the kernel's release/getRelease contract. It never
184
+ * claims that EMILIA holds funds or that the external provider is licensed.
185
+ */
186
+ export function createActionEscrowCustodianBridge({
187
+ adapter,
188
+ observationSigner,
189
+ now = () => new Date().toISOString(),
190
+ }: {
191
+ adapter?: Record<string, any>;
192
+ observationSigner?: Record<string, any>;
193
+ now?: () => string;
194
+ } = {}) {
195
+ if (!isRecord(adapter)
196
+ || adapter.kind !== 'external_custodian'
197
+ || !validString(adapter.provider, 128)
198
+ || !['sandbox', 'production'].includes(adapter.environment)
199
+ || typeof adapter.reconcileTransaction !== 'function'
200
+ || typeof adapter.releaseMilestone !== 'function'
201
+ || typeof adapter.requestMilestoneDisbursement !== 'function'
202
+ || !isRecord(observationSigner)
203
+ || !validString(observationSigner.key_id, 256)
204
+ || typeof now !== 'function') {
205
+ throw new TypeError('external custodian adapter and observation signer are required');
206
+ }
207
+ const privateKey = normalizePrivateKey(observationSigner.privateKey);
208
+
209
+ async function preflight(request) {
210
+ // adapter is validated above; the guard's narrowing does not carry into
211
+ // this hoisted function declaration's closure.
212
+ const reconciled = await adapter!.reconcileTransaction({
213
+ transactionId: request.release_action_template.custodian_transaction_id,
214
+ });
215
+ if (!providerResultMatches(
216
+ reconciled,
217
+ request,
218
+ adapter,
219
+ 'reconcile_transaction',
220
+ )
221
+ || reconciled.kind !== 'reconciled'
222
+ || !transactionMatches(reconciled.transaction, request)) {
223
+ throw new Error('custodian transaction does not match the signed release action');
224
+ }
225
+ return reconciled.transaction;
226
+ }
227
+
228
+ // observationSigner is validated above; the guard's narrowing does not
229
+ // carry into this hoisted function declaration's closure.
230
+ function signObservation(request, status, result) {
231
+ const observedAt = now();
232
+ if (!strictInstant(observedAt)) throw new Error('invalid custodian observation clock');
233
+ const transaction = transactionFromResult(result);
234
+ const payload = {
235
+ '@version': ACTION_ESCROW_CUSTODIAN_OBSERVATION_VERSION,
236
+ provider_id: result.provider,
237
+ environment: result.environment,
238
+ statement_type: 'release',
239
+ status,
240
+ agreement_digest: request.agreement_digest,
241
+ document_action_binding_digest: request.document_action_binding_digest,
242
+ milestone_id: request.milestone_id,
243
+ release_action_digest: request.release_action_digest,
244
+ parties_digest: request.parties_digest,
245
+ profile_digest: request.profile_digest,
246
+ provider_idempotency_key: request.idempotency_key,
247
+ provider_request_digest: request.request_digest,
248
+ provider_effect_reference: result.effect_reference,
249
+ provider_transaction_id: result.transaction_id,
250
+ provider_milestone_id: result.milestone_id,
251
+ amount: request.release_action_template.amount,
252
+ currency: request.release_action_template.currency,
253
+ destination_id: request.release_action_template.destination_id,
254
+ provider_snapshot_digest: canonicalDigest(transaction),
255
+ observed_at: observedAt,
256
+ };
257
+ const signature = crypto.sign(null, signingBytes(payload), privateKey);
258
+ return deepFreeze({
259
+ payload,
260
+ signature: {
261
+ algorithm: 'Ed25519',
262
+ key_id: observationSigner!.key_id,
263
+ value: signature.toString('base64url'),
264
+ },
265
+ });
266
+ }
267
+
268
+ return Object.freeze({
269
+ provider: adapter.provider,
270
+ environment: adapter.environment,
271
+ async release(untrustedRequest) {
272
+ const request = normalizeKernelRequest(untrustedRequest, adapter);
273
+ if (!request || request.method !== 'POST') {
274
+ throw new Error('invalid kernel release request');
275
+ }
276
+ await preflight(request);
277
+ const result = await adapter.releaseMilestone({
278
+ effectReference: request.idempotency_key,
279
+ transactionId: request.release_action_template.custodian_transaction_id,
280
+ milestoneId: request.release_action_template.custodian_milestone_id,
281
+ });
282
+ if (!providerResultMatches(
283
+ result,
284
+ request,
285
+ adapter,
286
+ 'release_milestone',
287
+ )
288
+ || !['released', 'release_submitted', 'provider_action_required'].includes(result.kind)
289
+ || (
290
+ ['released', 'release_submitted'].includes(result.kind)
291
+ && !transactionMatches(transactionFromResult(result), request)
292
+ )) {
293
+ throw new Error('custodian release outcome is not authoritative');
294
+ }
295
+ return { accepted: true };
296
+ },
297
+ async getRelease(untrustedRequest) {
298
+ const request = normalizeKernelRequest(untrustedRequest, adapter);
299
+ if (!request || request.method !== 'GET') {
300
+ throw new Error('invalid kernel reconciliation request');
301
+ }
302
+ await preflight(request);
303
+ const result = await adapter.requestMilestoneDisbursement({
304
+ effectReference: request.idempotency_key,
305
+ transactionId: request.release_action_template.custodian_transaction_id,
306
+ milestoneId: request.release_action_template.custodian_milestone_id,
307
+ });
308
+ const status = observationStatus(result);
309
+ const transaction = transactionFromResult(result);
310
+ if (!providerResultMatches(
311
+ result,
312
+ request,
313
+ adapter,
314
+ 'request_milestone_disbursement',
315
+ )
316
+ || !status
317
+ || !transaction
318
+ || !transactionMatches(transaction, request)) {
319
+ throw new Error('custodian release state is indeterminate');
320
+ }
321
+ return {
322
+ authenticated: true,
323
+ statement: signObservation(request, status, result),
324
+ };
325
+ },
326
+ });
327
+ }
328
+
329
+ export function createActionEscrowCustodianStatementVerifier({
330
+ operatorKeys,
331
+ providerId,
332
+ environment,
333
+ }: {
334
+ operatorKeys?: Record<string, any>;
335
+ providerId?: string;
336
+ environment?: string;
337
+ } = {}) {
338
+ if (!isRecord(operatorKeys)
339
+ || !validString(providerId, 128)
340
+ || !(environment === 'sandbox' || environment === 'production')) {
341
+ throw new TypeError('pinned operator keys and provider identity are required');
342
+ }
343
+ const pins = canonicalCopy(operatorKeys);
344
+ return async function verifyStatement(statement, expected) {
345
+ try {
346
+ if (!isRecord(statement)
347
+ || !isRecord(statement.payload)
348
+ || !isRecord(statement.signature)
349
+ || statement.signature.algorithm !== 'Ed25519'
350
+ || !validString(statement.signature.key_id, 256)
351
+ || !validString(statement.signature.value, 1024)) {
352
+ return { valid: false, reason: 'malformed_custodian_observation' };
353
+ }
354
+ const pin = pins[statement.signature.key_id];
355
+ if (!isRecord(pin) || typeof pin.public_key !== 'string') {
356
+ return { valid: false, reason: 'custodian_operator_key_not_pinned' };
357
+ }
358
+ const publicKey = crypto.createPublicKey({
359
+ key: Buffer.from(pin.public_key, 'base64url'),
360
+ type: 'spki',
361
+ format: 'der',
362
+ });
363
+ if (publicKey.asymmetricKeyType !== 'ed25519'
364
+ || !crypto.verify(
365
+ null,
366
+ signingBytes(statement.payload),
367
+ publicKey,
368
+ Buffer.from(statement.signature.value, 'base64url'),
369
+ )) {
370
+ return { valid: false, reason: 'custodian_observation_signature_invalid' };
371
+ }
372
+ const payload = statement.payload;
373
+ const exact = payload['@version'] === ACTION_ESCROW_CUSTODIAN_OBSERVATION_VERSION
374
+ && payload.provider_id === providerId
375
+ && payload.environment === environment
376
+ && payload.statement_type === expected.statement_type
377
+ && payload.agreement_digest === expected.agreement_digest
378
+ && payload.document_action_binding_digest
379
+ === expected.document_action_binding_digest
380
+ && payload.milestone_id === expected.milestone_id
381
+ && payload.release_action_digest === expected.release_action_digest
382
+ && payload.parties_digest === expected.parties_digest
383
+ && payload.profile_digest === expected.profile_digest
384
+ && payload.provider_idempotency_key === expected.provider_idempotency_key
385
+ && payload.provider_request_digest === expected.provider_request_digest
386
+ && payload.provider_effect_reference === expected.provider_idempotency_key
387
+ && payload.provider_transaction_id === expected.provider_transaction_id
388
+ && payload.provider_milestone_id === expected.provider_milestone_id
389
+ && payload.amount === expected.amount
390
+ && payload.currency === expected.currency
391
+ && payload.destination_id === expected.destination_id
392
+ && ['released', 'not_released', 'pending'].includes(payload.status)
393
+ && HASH.test(payload.provider_snapshot_digest)
394
+ && strictInstant(payload.observed_at);
395
+ if (!exact) return { valid: false, reason: 'custodian_observation_binding_mismatch' };
396
+ return {
397
+ valid: true,
398
+ authenticated: true,
399
+ statement_type: payload.statement_type,
400
+ status: payload.status,
401
+ statement_digest: canonicalDigest(statement),
402
+ provider_id: payload.provider_id,
403
+ agreement_digest: payload.agreement_digest,
404
+ document_action_binding_digest: payload.document_action_binding_digest,
405
+ milestone_id: payload.milestone_id,
406
+ release_action_digest: payload.release_action_digest,
407
+ parties_digest: payload.parties_digest,
408
+ profile_digest: payload.profile_digest,
409
+ provider_idempotency_key: payload.provider_idempotency_key,
410
+ provider_request_digest: payload.provider_request_digest,
411
+ provider_transaction_id: payload.provider_transaction_id,
412
+ provider_milestone_id: payload.provider_milestone_id,
413
+ amount: payload.amount,
414
+ currency: payload.currency,
415
+ destination_id: payload.destination_id,
416
+ };
417
+ } catch {
418
+ return { valid: false, reason: 'malformed_custodian_observation' };
419
+ }
420
+ };
421
+ }
422
+
423
+ export default Object.freeze({
424
+ ACTION_ESCROW_CUSTODIAN_OBSERVATION_VERSION,
425
+ createActionEscrowCustodianBridge,
426
+ createActionEscrowCustodianStatementVerifier,
427
+ });