@europeum-ebsi/cli 0.0.0 → 1.0.0-rc.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 (384) hide show
  1. package/LICENSE.txt +289 -289
  2. package/LICENSES.txt +538 -0
  3. package/README.md +1140 -98
  4. package/dist/api/client.d.ts +4 -0
  5. package/dist/api/client.d.ts.map +1 -0
  6. package/dist/api/client.js +14 -0
  7. package/dist/api/client.js.map +1 -0
  8. package/dist/api/fetch.d.ts +13 -0
  9. package/dist/api/fetch.d.ts.map +1 -0
  10. package/dist/api/fetch.js +30 -0
  11. package/dist/api/fetch.js.map +1 -0
  12. package/dist/api/params.d.ts +4 -0
  13. package/dist/api/params.d.ts.map +1 -0
  14. package/dist/api/params.js +9 -0
  15. package/dist/api/params.js.map +1 -0
  16. package/dist/auth/dcql.d.ts +5 -0
  17. package/dist/auth/dcql.d.ts.map +1 -0
  18. package/dist/auth/dcql.js +41 -0
  19. package/dist/auth/dcql.js.map +1 -0
  20. package/dist/auth/presentation.d.ts +30 -0
  21. package/dist/auth/presentation.d.ts.map +1 -0
  22. package/dist/auth/presentation.js +99 -0
  23. package/dist/auth/presentation.js.map +1 -0
  24. package/dist/auth/token.d.ts +11 -0
  25. package/dist/auth/token.d.ts.map +1 -0
  26. package/dist/auth/token.js +116 -0
  27. package/dist/auth/token.js.map +1 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +96 -10
  31. package/dist/cli.js.map +1 -1
  32. package/dist/commands/auth.d.ts +3 -0
  33. package/dist/commands/auth.d.ts.map +1 -0
  34. package/dist/commands/auth.js +99 -0
  35. package/dist/commands/auth.js.map +1 -0
  36. package/dist/commands/config-cmd.d.ts +3 -0
  37. package/dist/commands/config-cmd.d.ts.map +1 -0
  38. package/dist/commands/config-cmd.js +86 -0
  39. package/dist/commands/config-cmd.js.map +1 -0
  40. package/dist/commands/contracts-registry.d.ts +3 -0
  41. package/dist/commands/contracts-registry.d.ts.map +1 -0
  42. package/dist/commands/contracts-registry.js +132 -0
  43. package/dist/commands/contracts-registry.js.map +1 -0
  44. package/dist/commands/did-registry.d.ts +3 -0
  45. package/dist/commands/did-registry.d.ts.map +1 -0
  46. package/dist/commands/did-registry.js +110 -0
  47. package/dist/commands/did-registry.js.map +1 -0
  48. package/dist/commands/faucet.d.ts +3 -0
  49. package/dist/commands/faucet.d.ts.map +1 -0
  50. package/dist/commands/faucet.js +78 -0
  51. package/dist/commands/faucet.js.map +1 -0
  52. package/dist/commands/health.d.ts +3 -0
  53. package/dist/commands/health.d.ts.map +1 -0
  54. package/dist/commands/health.js +20 -0
  55. package/dist/commands/health.js.map +1 -0
  56. package/dist/commands/issuers-registry.d.ts +3 -0
  57. package/dist/commands/issuers-registry.d.ts.map +1 -0
  58. package/dist/commands/issuers-registry.js +340 -0
  59. package/dist/commands/issuers-registry.js.map +1 -0
  60. package/dist/commands/ledger.d.ts +3 -0
  61. package/dist/commands/ledger.d.ts.map +1 -0
  62. package/dist/commands/ledger.js +549 -372
  63. package/dist/commands/ledger.js.map +1 -1
  64. package/dist/commands/onboarding.d.ts +3 -0
  65. package/dist/commands/onboarding.d.ts.map +1 -0
  66. package/dist/commands/onboarding.js +301 -0
  67. package/dist/commands/onboarding.js.map +1 -0
  68. package/dist/commands/openapi.d.ts +3 -0
  69. package/dist/commands/openapi.d.ts.map +1 -0
  70. package/dist/commands/openapi.js +37 -0
  71. package/dist/commands/openapi.js.map +1 -0
  72. package/dist/commands/policies-registry.d.ts +3 -0
  73. package/dist/commands/policies-registry.d.ts.map +1 -0
  74. package/dist/commands/policies-registry.js +198 -0
  75. package/dist/commands/policies-registry.js.map +1 -0
  76. package/dist/commands/registry.d.ts +27 -0
  77. package/dist/commands/registry.d.ts.map +1 -0
  78. package/dist/commands/registry.js +62 -0
  79. package/dist/commands/registry.js.map +1 -0
  80. package/dist/commands/schemas-registry.d.ts +3 -0
  81. package/dist/commands/schemas-registry.d.ts.map +1 -0
  82. package/dist/commands/schemas-registry.js +231 -0
  83. package/dist/commands/schemas-registry.js.map +1 -0
  84. package/dist/commands/shared/args.d.ts +2 -0
  85. package/dist/commands/shared/args.d.ts.map +1 -0
  86. package/dist/commands/shared/args.js +4 -0
  87. package/dist/commands/shared/args.js.map +1 -0
  88. package/dist/commands/shared/wallet-opts.d.ts +9 -0
  89. package/dist/commands/shared/wallet-opts.d.ts.map +1 -0
  90. package/dist/commands/shared/wallet-opts.js +44 -0
  91. package/dist/commands/shared/wallet-opts.js.map +1 -0
  92. package/dist/commands/timestamp.d.ts +3 -0
  93. package/dist/commands/timestamp.d.ts.map +1 -0
  94. package/dist/commands/timestamp.js +250 -0
  95. package/dist/commands/timestamp.js.map +1 -0
  96. package/dist/commands/track-and-trace.d.ts +3 -0
  97. package/dist/commands/track-and-trace.d.ts.map +1 -0
  98. package/dist/commands/track-and-trace.js +235 -0
  99. package/dist/commands/track-and-trace.js.map +1 -0
  100. package/dist/commands/wallet.d.ts +3 -0
  101. package/dist/commands/wallet.d.ts.map +1 -0
  102. package/dist/commands/wallet.js +123 -0
  103. package/dist/commands/wallet.js.map +1 -0
  104. package/dist/config/config.d.ts +45 -0
  105. package/dist/config/config.d.ts.map +1 -0
  106. package/dist/config/config.js +111 -0
  107. package/dist/config/config.js.map +1 -0
  108. package/dist/config/ebsi-env.d.ts +4 -0
  109. package/dist/config/ebsi-env.d.ts.map +1 -0
  110. package/dist/config/ebsi-env.js +37 -0
  111. package/dist/config/ebsi-env.js.map +1 -0
  112. package/dist/crypto/wallet.d.ts +34 -0
  113. package/dist/crypto/wallet.d.ts.map +1 -0
  114. package/dist/crypto/wallet.js +100 -0
  115. package/dist/crypto/wallet.js.map +1 -0
  116. package/dist/index.d.ts +3 -0
  117. package/dist/index.d.ts.map +1 -0
  118. package/dist/index.js +15 -6
  119. package/dist/index.js.map +1 -1
  120. package/dist/ledger/read.d.ts +11 -0
  121. package/dist/ledger/read.d.ts.map +1 -0
  122. package/dist/ledger/read.js +24 -0
  123. package/dist/ledger/read.js.map +1 -0
  124. package/dist/ledger/registries.d.ts +25 -0
  125. package/dist/ledger/registries.d.ts.map +1 -0
  126. package/dist/ledger/registries.js +111 -0
  127. package/dist/ledger/registries.js.map +1 -0
  128. package/dist/ledger/write.d.ts +43 -0
  129. package/dist/ledger/write.d.ts.map +1 -0
  130. package/dist/ledger/write.js +119 -0
  131. package/dist/ledger/write.js.map +1 -0
  132. package/dist/onboarding/vc.d.ts +18 -0
  133. package/dist/onboarding/vc.d.ts.map +1 -0
  134. package/dist/onboarding/vc.js +72 -0
  135. package/dist/onboarding/vc.js.map +1 -0
  136. package/dist/output/format.d.ts +7 -0
  137. package/dist/output/format.d.ts.map +1 -0
  138. package/dist/output/format.js +94 -0
  139. package/dist/output/format.js.map +1 -0
  140. package/dist/tui/App.d.ts +3 -0
  141. package/dist/tui/App.d.ts.map +1 -0
  142. package/dist/tui/App.js +99 -0
  143. package/dist/tui/App.js.map +1 -0
  144. package/dist/tui/CommandPalette.d.ts +8 -0
  145. package/dist/tui/CommandPalette.d.ts.map +1 -0
  146. package/dist/tui/CommandPalette.js +105 -0
  147. package/dist/tui/CommandPalette.js.map +1 -0
  148. package/package.json +66 -108
  149. package/src/api/client.ts +26 -0
  150. package/src/api/fetch.ts +53 -0
  151. package/src/api/params.ts +17 -0
  152. package/src/auth/dcql.ts +84 -0
  153. package/src/auth/presentation.ts +255 -0
  154. package/src/auth/token.ts +244 -0
  155. package/src/cli.ts +164 -0
  156. package/src/commands/auth.ts +119 -0
  157. package/src/commands/config-cmd.ts +122 -0
  158. package/src/commands/contracts-registry.ts +156 -0
  159. package/src/commands/did-registry.ts +126 -0
  160. package/src/commands/faucet.ts +112 -0
  161. package/src/commands/health.ts +21 -0
  162. package/src/commands/issuers-registry.ts +385 -0
  163. package/src/commands/ledger.ts +777 -0
  164. package/src/commands/onboarding.ts +411 -0
  165. package/src/commands/openapi.ts +42 -0
  166. package/src/commands/policies-registry.ts +218 -0
  167. package/src/commands/registry.ts +152 -0
  168. package/src/commands/schemas-registry.ts +255 -0
  169. package/src/commands/shared/args.ts +14 -0
  170. package/src/commands/shared/wallet-opts.ts +85 -0
  171. package/src/commands/timestamp.ts +272 -0
  172. package/src/commands/track-and-trace.ts +263 -0
  173. package/src/commands/wallet.ts +175 -0
  174. package/src/config/config.ts +275 -0
  175. package/src/config/ebsi-env.ts +67 -0
  176. package/src/crypto/wallet.ts +291 -0
  177. package/src/index.ts +24 -0
  178. package/src/ledger/read.ts +70 -0
  179. package/src/ledger/registries.ts +285 -0
  180. package/src/ledger/write.ts +381 -0
  181. package/src/onboarding/vc.ts +205 -0
  182. package/src/output/format.ts +157 -0
  183. package/src/tui/App.tsx +282 -0
  184. package/src/tui/CommandPalette.tsx +223 -0
  185. package/bin/cli.js +0 -13
  186. package/dist/abi/pilot/DidRegistry.js +0 -568
  187. package/dist/abi/pilot/DidRegistry.js.map +0 -1
  188. package/dist/abi/pilot/Ptr.js +0 -666
  189. package/dist/abi/pilot/Ptr.js.map +0 -1
  190. package/dist/abi/pilot/SchemaSCRegistry.js +0 -264
  191. package/dist/abi/pilot/SchemaSCRegistry.js.map +0 -1
  192. package/dist/abi/pilot/Tcr.js +0 -715
  193. package/dist/abi/pilot/Tcr.js.map +0 -1
  194. package/dist/abi/pilot/Timestamp.js +0 -658
  195. package/dist/abi/pilot/Timestamp.js.map +0 -1
  196. package/dist/abi/pilot/Tir.js +0 -428
  197. package/dist/abi/pilot/Tir.js.map +0 -1
  198. package/dist/abi/pilot/TnT.js +0 -842
  199. package/dist/abi/pilot/TnT.js.map +0 -1
  200. package/dist/abi/pilot/Tpr.js +0 -492
  201. package/dist/abi/pilot/Tpr.js.map +0 -1
  202. package/dist/abi/test/DidRegistry.js +0 -568
  203. package/dist/abi/test/DidRegistry.js.map +0 -1
  204. package/dist/abi/test/Ptr.js +0 -666
  205. package/dist/abi/test/Ptr.js.map +0 -1
  206. package/dist/abi/test/SchemaSCRegistry.js +0 -300
  207. package/dist/abi/test/SchemaSCRegistry.js.map +0 -1
  208. package/dist/abi/test/Tcr.js +0 -715
  209. package/dist/abi/test/Tcr.js.map +0 -1
  210. package/dist/abi/test/Timestamp.js +0 -658
  211. package/dist/abi/test/Timestamp.js.map +0 -1
  212. package/dist/abi/test/Tir.js +0 -428
  213. package/dist/abi/test/Tir.js.map +0 -1
  214. package/dist/abi/test/TnT.js +0 -842
  215. package/dist/abi/test/TnT.js.map +0 -1
  216. package/dist/abi/test/Tpr.js +0 -492
  217. package/dist/abi/test/Tpr.js.map +0 -1
  218. package/dist/app.js +0 -659
  219. package/dist/app.js.map +0 -1
  220. package/dist/buildParam/didr.js +0 -374
  221. package/dist/buildParam/didr.js.map +0 -1
  222. package/dist/buildParam/index.js +0 -53
  223. package/dist/buildParam/index.js.map +0 -1
  224. package/dist/buildParam/ptr.js +0 -80
  225. package/dist/buildParam/ptr.js.map +0 -1
  226. package/dist/buildParam/tcr.js +0 -36
  227. package/dist/buildParam/tcr.js.map +0 -1
  228. package/dist/buildParam/timestamp.js +0 -350
  229. package/dist/buildParam/timestamp.js.map +0 -1
  230. package/dist/buildParam/tir.js +0 -110
  231. package/dist/buildParam/tir.js.map +0 -1
  232. package/dist/buildParam/tnt.js +0 -214
  233. package/dist/buildParam/tnt.js.map +0 -1
  234. package/dist/buildParam/tpr.js +0 -91
  235. package/dist/buildParam/tpr.js.map +0 -1
  236. package/dist/buildParam/tsr.js +0 -115
  237. package/dist/buildParam/tsr.js.map +0 -1
  238. package/dist/commands/authorisation.js +0 -144
  239. package/dist/commands/authorisation.js.map +0 -1
  240. package/dist/commands/compute.js +0 -680
  241. package/dist/commands/compute.js.map +0 -1
  242. package/dist/commands/conformance.js +0 -813
  243. package/dist/commands/conformance.js.map +0 -1
  244. package/dist/commands/hardwarewallet.js +0 -41
  245. package/dist/commands/hardwarewallet.js.map +0 -1
  246. package/dist/commands/index.js +0 -8
  247. package/dist/commands/index.js.map +0 -1
  248. package/dist/commands/ptr.js +0 -54
  249. package/dist/commands/ptr.js.map +0 -1
  250. package/dist/commands/tcr.js +0 -50
  251. package/dist/commands/tcr.js.map +0 -1
  252. package/dist/commands/tir.js +0 -64
  253. package/dist/commands/tir.js.map +0 -1
  254. package/dist/commands/tnl.js +0 -81
  255. package/dist/commands/tnl.js.map +0 -1
  256. package/dist/commands/tsr.js +0 -45
  257. package/dist/commands/tsr.js.map +0 -1
  258. package/dist/commands/view.js +0 -53
  259. package/dist/commands/view.js.map +0 -1
  260. package/dist/config.js +0 -497
  261. package/dist/config.js.map +0 -1
  262. package/dist/interfaces/context.js +0 -2
  263. package/dist/interfaces/context.js.map +0 -1
  264. package/dist/interfaces/contracts/ProxyFactory.js +0 -2
  265. package/dist/interfaces/contracts/ProxyFactory.js.map +0 -1
  266. package/dist/interfaces/contracts/ProxyTemplateRegistry.js +0 -2
  267. package/dist/interfaces/contracts/ProxyTemplateRegistry.js.map +0 -1
  268. package/dist/interfaces/contracts/SchemaSCRegistry.js +0 -2
  269. package/dist/interfaces/contracts/SchemaSCRegistry.js.map +0 -1
  270. package/dist/interfaces/contracts/common.js +0 -2
  271. package/dist/interfaces/contracts/common.js.map +0 -1
  272. package/dist/interfaces/index.js +0 -5
  273. package/dist/interfaces/index.js.map +0 -1
  274. package/dist/interfaces/jsonrpc.interface.js +0 -2
  275. package/dist/interfaces/jsonrpc.interface.js.map +0 -1
  276. package/dist/interfaces/paginated-list.interface.js +0 -2
  277. package/dist/interfaces/paginated-list.interface.js.map +0 -1
  278. package/dist/interfaces/unsigned-transaction.interface.js +0 -2
  279. package/dist/interfaces/unsigned-transaction.interface.js.map +0 -1
  280. package/dist/interfaces/utils.interface.js +0 -2
  281. package/dist/interfaces/utils.interface.js.map +0 -1
  282. package/dist/programs/migrateDid.js +0 -159
  283. package/dist/programs/migrateDid.js.map +0 -1
  284. package/dist/programs/migrateDids.js +0 -232
  285. package/dist/programs/migrateDids.js.map +0 -1
  286. package/dist/programs/migrateTsr.js +0 -201
  287. package/dist/programs/migrateTsr.js.map +0 -1
  288. package/dist/scripts/accreditAndAuthorize/conformance/step1 +0 -34
  289. package/dist/scripts/accreditAndAuthorize/conformance/step2 +0 -18
  290. package/dist/scripts/accreditAndAuthorize/conformance/step3 +0 -9
  291. package/dist/scripts/accreditAndAuthorize/conformance/step4 +0 -27
  292. package/dist/scripts/accreditAndAuthorize/conformance/step5 +0 -13
  293. package/dist/scripts/accreditAndAuthorize/conformance/step6 +0 -14
  294. package/dist/scripts/accreditAndAuthorize/conformance/step7 +0 -7
  295. package/dist/scripts/accreditAndAuthorize/test/step1 +0 -34
  296. package/dist/scripts/accreditAndAuthorize/test/step2 +0 -18
  297. package/dist/scripts/accreditAndAuthorize/test/step3 +0 -9
  298. package/dist/scripts/accreditAndAuthorize/test/step4 +0 -27
  299. package/dist/scripts/accreditAndAuthorize/test/step5 +0 -13
  300. package/dist/scripts/accreditAndAuthorize/test/step6 +0 -14
  301. package/dist/scripts/accreditAndAuthorize/test/step7 +0 -7
  302. package/dist/scripts/accreditTI +0 -21
  303. package/dist/scripts/assets/Nodes.json +0 -27
  304. package/dist/scripts/assets/vcdm1.1/CTRevocableCredential.json +0 -30
  305. package/dist/scripts/assets/vcdm1.1/CredentialToAttestVerifiableAuthorisationForTrustChain.json +0 -29
  306. package/dist/scripts/assets/vcdm1.1/Nodes.json +0 -27
  307. package/dist/scripts/assets/vcdm1.1/TrustedNodesList.json +0 -35
  308. package/dist/scripts/assets/vcdm1.1/VerifiableAccreditationToAccredit.json +0 -35
  309. package/dist/scripts/assets/vcdm1.1/VerifiableAccreditationToAttest.json +0 -33
  310. package/dist/scripts/assets/vcdm1.1/VerifiableAuthorisationForTrustChain.json +0 -22
  311. package/dist/scripts/assets/vcdm1.1/VerifiableAuthorisationToInvoke.json +0 -24
  312. package/dist/scripts/assets/vcdm1.1/VerifiableAuthorisationToOnboard.json +0 -24
  313. package/dist/scripts/assets/vcdm2.0/CredentialToAttestVerifiableAuthorisationForTrustChain.json +0 -29
  314. package/dist/scripts/assets/vcdm2.0/TrustedNodesList.json +0 -36
  315. package/dist/scripts/assets/vcdm2.0/VerifiableAccreditationToAccredit.json +0 -40
  316. package/dist/scripts/assets/vcdm2.0/VerifiableAccreditationToAttest.json +0 -38
  317. package/dist/scripts/assets/vcdm2.0/VerifiableAuthorisationForTrustChain.json +0 -30
  318. package/dist/scripts/assets/vcdm2.0/VerifiableAuthorisationToInvoke.json +0 -24
  319. package/dist/scripts/assets/vcdm2.0/VerifiableAuthorisationToOnboard.json +0 -23
  320. package/dist/scripts/bootstrap/0a-loadTPROperator +0 -5
  321. package/dist/scripts/bootstrap/0b-loadAdmin +0 -8
  322. package/dist/scripts/bootstrap/1-populateTPR +0 -92
  323. package/dist/scripts/bootstrap/2-populateDID +0 -6
  324. package/dist/scripts/bootstrap/3-populateTimestamp +0 -9
  325. package/dist/scripts/bootstrap/4-populateTIR +0 -8
  326. package/dist/scripts/bootstrap/5-populateTSR +0 -85
  327. package/dist/scripts/bootstrap/6-setupConformanceIssuer +0 -35
  328. package/dist/scripts/bootstrap/README.md +0 -218
  329. package/dist/scripts/issueVcInvoke +0 -10
  330. package/dist/scripts/issueVcOnboard +0 -9
  331. package/dist/scripts/issueVcRootTAO +0 -11
  332. package/dist/scripts/issueVcTAO +0 -12
  333. package/dist/scripts/issueVcTI +0 -12
  334. package/dist/scripts/issueVcTnl +0 -32
  335. package/dist/scripts/issue_CTRevocableCredential +0 -12
  336. package/dist/scripts/issue_SelfAttestationSupportOffice +0 -10
  337. package/dist/scripts/issue_VerifiableAccreditationToAccredit +0 -11
  338. package/dist/scripts/issue_VerifiableAccreditationToAttest +0 -11
  339. package/dist/scripts/issue_VerifiableAuthorisationForTrustChain +0 -10
  340. package/dist/scripts/issue_VerifiableAuthorisationToOnboard +0 -9
  341. package/dist/scripts/preregisterIssuer +0 -6
  342. package/dist/scripts/registerDidDocument +0 -15
  343. package/dist/scripts/registerIssuer +0 -6
  344. package/dist/scripts/updateVcRootTAO +0 -10
  345. package/dist/scripts/updateVcTAO +0 -11
  346. package/dist/scripts/updateVcTI +0 -11
  347. package/dist/scripts/vcdm2.0/issueSelfAttestationSupportOffice +0 -10
  348. package/dist/scripts/vcdm2.0/issueVcInvoke +0 -12
  349. package/dist/scripts/vcdm2.0/issueVcOnboard +0 -11
  350. package/dist/scripts/vcdm2.0/issueVcRootTAO +0 -14
  351. package/dist/scripts/vcdm2.0/issueVcTAO +0 -15
  352. package/dist/scripts/vcdm2.0/issueVcTI +0 -15
  353. package/dist/scripts/vcdm2.0/issueVcTnl +0 -34
  354. package/dist/scripts/vcdm2.0/registerDidDocument +0 -15
  355. package/dist/scripts/vcdm2.0/updateVcRootTAO +0 -13
  356. package/dist/scripts/vcdm2.0/updateVcTAO +0 -14
  357. package/dist/scripts/vcdm2.0/updateVcTI +0 -14
  358. package/dist/scripts/vcdm2.0/verifyVcTnl +0 -10
  359. package/dist/scripts/verifyVcTnl +0 -10
  360. package/dist/scripts/wct/accreditAndAuthorize +0 -133
  361. package/dist/scripts/wct/accreditAndAuthorize2 +0 -89
  362. package/dist/scripts/wct/holderWallet +0 -39
  363. package/dist/scripts/wct/holderWallet2 +0 -39
  364. package/dist/scripts/wct/issueToHolder +0 -38
  365. package/dist/scripts/wct/issueToHolder2 +0 -38
  366. package/dist/scripts/wct/pda1 +0 -3
  367. package/dist/scripts/wct/verifier +0 -8
  368. package/dist/scripts/wct/verifier2 +0 -7
  369. package/dist/utils/Client.js +0 -155
  370. package/dist/utils/Client.js.map +0 -1
  371. package/dist/utils/HardwareWallet.js +0 -326
  372. package/dist/utils/HardwareWallet.js.map +0 -1
  373. package/dist/utils/http.js +0 -132
  374. package/dist/utils/http.js.map +0 -1
  375. package/dist/utils/index.js +0 -8
  376. package/dist/utils/index.js.map +0 -1
  377. package/dist/utils/jsonrpc.js +0 -38
  378. package/dist/utils/jsonrpc.js.map +0 -1
  379. package/dist/utils/print.js +0 -56
  380. package/dist/utils/print.js.map +0 -1
  381. package/dist/utils/utils.js +0 -427
  382. package/dist/utils/utils.js.map +0 -1
  383. package/dist/utils/vcdm.js +0 -47
  384. package/dist/utils/vcdm.js.map +0 -1
@@ -0,0 +1,777 @@
1
+ import type { components } from "@europeum-ebsi/api-contract/types";
2
+
3
+ import { readFileSync } from "node:fs";
4
+
5
+ import type { CliConfig } from "../config/config.ts";
6
+ import type { WalletDetails } from "../crypto/wallet.ts";
7
+ import type { GasOverrides } from "../ledger/write.ts";
8
+ import type { CommandDescriptor } from "./registry.ts";
9
+
10
+ import { getClient, unwrap } from "../api/fetch.ts";
11
+ import { validateScope } from "../auth/presentation.ts";
12
+ import { getAccessToken } from "../auth/token.ts";
13
+ import { readFromRegistry } from "../ledger/read.ts";
14
+ import {
15
+ defaultScopeFor,
16
+ deriveScopeForRegistries,
17
+ REGISTRIES,
18
+ REGISTRY_NAMES,
19
+ } from "../ledger/registries.ts";
20
+ import { signWriteBatch, writeToRegistry } from "../ledger/write.ts";
21
+ import { requiredArg } from "./shared/args.ts";
22
+ import { resolveWallet, WALLET_KEY_OPTIONS } from "./shared/wallet-opts.ts";
23
+
24
+ /**
25
+ * One entry of a generic `ledger batch` JSON-RPC request, before the
26
+ * `jsonrpc` field is stamped on. `id` is intentionally optional — an entry
27
+ * without one is a JSON-RPC notification and gets no response entry, matching
28
+ * the generated `components["schemas"]["JsonRpcPayload"]["id"]` type, which
29
+ * is likewise optional.
30
+ */
31
+ interface JsonRpcBatchEntry {
32
+ id?: number | string;
33
+ jsonrpc: "2.0";
34
+ method: string;
35
+ params?: JsonRpcParams;
36
+ }
37
+
38
+ type JsonRpcBatchPayload = components["schemas"]["JsonRpcBatchPayload"];
39
+ type JsonRpcParams = components["schemas"]["JsonRpcPayload"]["params"];
40
+
41
+ /**
42
+ * One entry of a `ledger write-batch` file: a registry function call, the
43
+ * same shape `ledger write` takes as separate positional args.
44
+ */
45
+ interface WriteBatchFileEntry {
46
+ args: unknown[];
47
+ function: string;
48
+ registry: string;
49
+ to?: string;
50
+ }
51
+
52
+ /**
53
+ * Validates and normalises one raw JSON value from a `ledger batch` source
54
+ * file into a well-formed JSON-RPC request, stamping `jsonrpc: "2.0"`.
55
+ */
56
+ function normalizeBatchEntry(entry: unknown, index: number): JsonRpcBatchEntry {
57
+ const position = `Batch entry #${(index + 1).toString()}`;
58
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
59
+ throw new Error(
60
+ `${position} must be a JSON object with a "method" field (e.g. {"method": "eth_blockNumber"}).`,
61
+ );
62
+ }
63
+ const { id, method, params } = entry as Record<string, unknown>;
64
+ if (typeof method !== "string" || method === "") {
65
+ throw new Error(`${position} is missing a "method" string.`);
66
+ }
67
+ if (params !== undefined && !Array.isArray(params)) {
68
+ throw new Error(`${position}: "params" must be a JSON array when present.`);
69
+ }
70
+ if (id !== undefined && typeof id !== "number" && typeof id !== "string") {
71
+ throw new Error(
72
+ `${position}: "id" must be a number or string when present.`,
73
+ );
74
+ }
75
+
76
+ return {
77
+ ...(id !== undefined && { id: id }),
78
+ jsonrpc: "2.0",
79
+ method,
80
+ ...(params !== undefined && { params: params as JsonRpcParams }),
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Parses one `--gas-limit`/`--gas-price` value (decimal or `0x`-prefixed
86
+ * hex, both accepted by `BigInt()`), throwing a CLI-style error — naming the
87
+ * flag — instead of a raw `SyntaxError`/`RangeError` on a bad value.
88
+ */
89
+ function parseGasBigInt(raw: string, flag: string): bigint {
90
+ try {
91
+ return BigInt(raw);
92
+ } catch (error) {
93
+ const message = error instanceof Error ? error.message : String(error);
94
+ throw new Error(`Invalid ${flag} value "${raw}": ${message}`, {
95
+ cause: error,
96
+ });
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Parses the shared `--gas-limit <value>` / `--gas-price <value>` options
102
+ * (decimal or `0x`-prefixed hex, both accepted by `BigInt()`) into a
103
+ * `GasOverrides`. Both are advanced escape hatches — by default `ledger
104
+ * write`/`ledger write-batch` derive gas dynamically from the node (see
105
+ * `../ledger/write.ts`). Returns `undefined` when neither is set, so callers
106
+ * can pass the result straight through as `gas`.
107
+ */
108
+ function parseGasOverrides(
109
+ opts: Record<string, string>,
110
+ ): GasOverrides | undefined {
111
+ const gasLimitRaw = opts["gasLimit"];
112
+ const gasPriceRaw = opts["gasPrice"];
113
+ if (gasLimitRaw === undefined && gasPriceRaw === undefined) {
114
+ return undefined;
115
+ }
116
+
117
+ return {
118
+ ...(gasLimitRaw !== undefined && {
119
+ gasLimit: parseGasBigInt(gasLimitRaw, "--gas-limit"),
120
+ }),
121
+ ...(gasPriceRaw !== undefined && {
122
+ gasPrice: parseGasBigInt(gasPriceRaw, "--gas-price"),
123
+ }),
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Parses a JSON-array CLI argument (a registry function's args, or a raw
129
+ * JSON-RPC params list), throwing a CLI-style error — naming the argument —
130
+ * rather than a raw SyntaxError, when it isn't valid JSON or isn't an array.
131
+ */
132
+ function parseJsonArray(raw: string, argName: string): unknown[] {
133
+ let parsed: unknown;
134
+ try {
135
+ parsed = JSON.parse(raw);
136
+ } catch (error) {
137
+ /* v8 ignore next -- JSON.parse only ever throws a real Error/SyntaxError */
138
+ const message = error instanceof Error ? error.message : "parse error";
139
+ throw new Error(`Invalid ${argName} JSON: ${message}`, { cause: error });
140
+ }
141
+ if (!Array.isArray(parsed)) {
142
+ throw new TypeError(`${argName} must be a JSON array`);
143
+ }
144
+ return parsed;
145
+ }
146
+
147
+ /**
148
+ * Parses and validates a `ledger write-batch` file's JSON contents.
149
+ */
150
+ function parseWriteBatchFile(raw: string): WriteBatchFileEntry[] {
151
+ let parsed: unknown;
152
+ try {
153
+ parsed = JSON.parse(raw);
154
+ } catch (error) {
155
+ /* v8 ignore next -- JSON.parse only ever throws a real Error/SyntaxError */
156
+ const message = error instanceof Error ? error.message : "parse error";
157
+ throw new Error(`Invalid JSON: ${message}`, { cause: error });
158
+ }
159
+ if (!Array.isArray(parsed) || parsed.length === 0) {
160
+ throw new Error(
161
+ "Batch file must contain a non-empty JSON array of write entries " +
162
+ '(each: {"registry", "function", "args", "to"?}).',
163
+ );
164
+ }
165
+
166
+ return parsed.map((entry, index) => {
167
+ const position = `Entry #${(index + 1).toString()}`;
168
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
169
+ throw new Error(
170
+ `${position} must be a JSON object with "registry", "function", and "args".`,
171
+ );
172
+ }
173
+ const {
174
+ args,
175
+ function: fn,
176
+ registry,
177
+ to,
178
+ } = entry as Record<string, unknown>;
179
+ if (typeof registry !== "string" || registry === "") {
180
+ throw new Error(`${position} is missing a "registry" string.`);
181
+ }
182
+ if (typeof fn !== "string" || fn === "") {
183
+ throw new Error(`${position} is missing a "function" string.`);
184
+ }
185
+ if (!Array.isArray(args)) {
186
+ throw new TypeError(`${position}: "args" must be a JSON array.`);
187
+ }
188
+ if (to !== undefined && typeof to !== "string") {
189
+ throw new Error(`${position}: "to" must be a string when present.`);
190
+ }
191
+ return { args, function: fn, registry, ...(to !== undefined && { to }) };
192
+ });
193
+ }
194
+
195
+ /**
196
+ * Reads all of stdin and returns it as a UTF-8 string.
197
+ */
198
+ async function readStdin(): Promise<string> {
199
+ const chunks: Buffer[] = [];
200
+ for await (const chunk of process.stdin) {
201
+ chunks.push(chunk as Buffer);
202
+ }
203
+ return Buffer.concat(chunks).toString("utf8");
204
+ }
205
+
206
+ /**
207
+ * Resolves the Bearer token for `ledger write`/`ledger write-batch`: either
208
+ * mints a fresh one via `--auto-token` (validating `--scope` up front so an
209
+ * illegal combination fails locally with a clear message instead of a
210
+ * generic API error) or reads a pre-obtained one from `--token`/config.
211
+ */
212
+ async function resolveWriteToken(
213
+ opts: Record<string, string>,
214
+ config: CliConfig,
215
+ wallet: WalletDetails,
216
+ defaultScope: string,
217
+ ): Promise<string> {
218
+ if (opts["autoToken"]) {
219
+ const scope = opts["scope"] ?? defaultScope;
220
+ validateScope(scope);
221
+ const vcFile = opts["vc"];
222
+ const vcJwt = vcFile ? readFileSync(vcFile, "utf8").trim() : undefined;
223
+ return getAccessToken({
224
+ config,
225
+ scope,
226
+ wallet,
227
+ ...(vcJwt !== undefined && { vcJwt }),
228
+ });
229
+ }
230
+
231
+ const resolvedToken = opts["token"] ?? config.token;
232
+ if (!resolvedToken) {
233
+ throw new Error(
234
+ "No access token found. " +
235
+ "Use --auto-token to mint one via the VP flow, " +
236
+ "or provide --token <jwt> / EBSI_ACCESS_TOKEN / `ebsi config set token <jwt>`.",
237
+ );
238
+ }
239
+ return resolvedToken;
240
+ }
241
+
242
+ export const ledgerCommands: CommandDescriptor[] = [
243
+ {
244
+ args: [
245
+ {
246
+ description:
247
+ "JSON-RPC method to invoke (e.g. eth_getBlockByNumber, eth_sendRawTransaction)",
248
+ example: "eth_getBlockByNumber",
249
+ name: "method",
250
+ required: true,
251
+ },
252
+ {
253
+ description:
254
+ "JSON array of parameters encoded as a string (e.g. '[\"latest\", false]'). Omit or pass '[]' for methods with no params.",
255
+ example: '["latest", false]',
256
+ name: "params",
257
+ required: false,
258
+ },
259
+ ],
260
+ group: "Ledger",
261
+ async handler(args, opts, config) {
262
+ const method = requiredArg(args, "method");
263
+ const rawParams = args["params"];
264
+
265
+ let params: NonNullable<JsonRpcParams> = [];
266
+ if (rawParams !== undefined && rawParams !== "") {
267
+ try {
268
+ const parsed: unknown = JSON.parse(rawParams);
269
+ if (!Array.isArray(parsed)) {
270
+ throw new TypeError("params must be a JSON array");
271
+ }
272
+ params = parsed as NonNullable<JsonRpcParams>;
273
+ } catch (error) {
274
+ /* v8 ignore next -- JSON.parse only ever throws a real Error/SyntaxError */
275
+ const message =
276
+ error instanceof Error ? error.message : "parse error";
277
+ throw new Error(`Invalid params JSON: ${message}`, { cause: error });
278
+ }
279
+ }
280
+
281
+ const id = Number(opts["id"] ?? 1);
282
+ const client = getClient(config);
283
+ const result = await client.POST("/ledger", {
284
+ body: { id, jsonrpc: "2.0", method, params },
285
+ });
286
+ return unwrap(result);
287
+ },
288
+ id: "ledger.call",
289
+ options: [
290
+ {
291
+ defaultValue: "1",
292
+ description: "JSON-RPC request id (default: 1)",
293
+ flags: "--id <n>",
294
+ },
295
+ ],
296
+ segments: ["ledger", "call"],
297
+ summary:
298
+ "Send a JSON-RPC request to the Besu node via POST /ledger. " +
299
+ "Read methods (eth_getBlock*, eth_getTransaction*, ...) are forwarded anonymously. " +
300
+ "Write methods (eth_sendRawTransaction) require a Bearer token via --token, " +
301
+ "EBSI_ACCESS_TOKEN env var, or `ebsi config set token <jwt>`. " +
302
+ "The caller is responsible for building and signing the raw transaction.",
303
+ },
304
+
305
+ {
306
+ args: [
307
+ {
308
+ description:
309
+ "Block number (hex, e.g. 0x1e240) or tag (latest, earliest, pending)",
310
+ example: "latest",
311
+ name: "blockNumberOrTag",
312
+ required: true,
313
+ },
314
+ ],
315
+ group: "Ledger",
316
+ async handler(args, _opts, config) {
317
+ const tag = requiredArg(args, "blockNumberOrTag", "latest");
318
+ const client = getClient(config);
319
+ const result = await client.POST("/ledger", {
320
+ body: {
321
+ id: 1,
322
+ jsonrpc: "2.0",
323
+ method: "eth_getBlockByNumber",
324
+ params: [tag, false],
325
+ },
326
+ });
327
+ return unwrap(result);
328
+ },
329
+ id: "ledger.block",
330
+ options: [],
331
+ segments: ["ledger", "block"],
332
+ summary:
333
+ "Get a block by number or tag (eth_getBlockByNumber). Shorthand for `ledger call eth_getBlockByNumber`.",
334
+ },
335
+
336
+ {
337
+ args: [
338
+ {
339
+ description: "Transaction hash (0x-prefixed hex)",
340
+ example:
341
+ "0x88df016429689c079f3b2f6ad39fa052532c56795b733da78a91ebe6a713944b",
342
+ name: "hash",
343
+ required: true,
344
+ },
345
+ ],
346
+ group: "Ledger",
347
+ async handler(args, _opts, config) {
348
+ const hash = requiredArg(args, "hash");
349
+ const client = getClient(config);
350
+ const result = await client.POST("/ledger", {
351
+ body: {
352
+ id: 1,
353
+ jsonrpc: "2.0",
354
+ method: "eth_getTransactionByHash",
355
+ params: [hash],
356
+ },
357
+ });
358
+ return unwrap(result);
359
+ },
360
+ id: "ledger.tx",
361
+ options: [],
362
+ segments: ["ledger", "tx"],
363
+ summary:
364
+ "Get a transaction by hash (eth_getTransactionByHash). Shorthand for `ledger call eth_getTransactionByHash`.",
365
+ },
366
+
367
+ {
368
+ args: [
369
+ {
370
+ description: "Registry name: " + REGISTRY_NAMES.join(", "),
371
+ example: "did-registry",
372
+ name: "registry",
373
+ required: true,
374
+ },
375
+ {
376
+ description:
377
+ "Smart-contract function to call (e.g. insertDidDocument, addIssuer)",
378
+ example: "insertDidDocument",
379
+ name: "function",
380
+ required: true,
381
+ },
382
+ {
383
+ description:
384
+ 'Function arguments as a JSON array string (e.g. \'["did:ebsi:z123", "..."]\'). ' +
385
+ "Types must match the contract ABI exactly.",
386
+ example:
387
+ '["did:ebsi:z123", "{}", "thumbprint", "0xpubkey", true, 0, 9999999999]',
388
+ name: "args",
389
+ required: true,
390
+ },
391
+ ],
392
+ group: "Ledger",
393
+ async handler(args, opts, config) {
394
+ const registryName = requiredArg(args, "registry");
395
+ const functionName = requiredArg(args, "function");
396
+ const argsRaw = requiredArg(args, "args");
397
+
398
+ const registry = REGISTRIES[registryName];
399
+ if (!registry) {
400
+ throw new Error(
401
+ `Unknown registry "${registryName}". Known registries: ${REGISTRY_NAMES.join(", ")}`,
402
+ );
403
+ }
404
+
405
+ const functionArgs = parseJsonArray(argsRaw, "args");
406
+
407
+ // Resolve contract address: --to → env var → error
408
+ const toOpt = opts["to"];
409
+ const contractAddress = toOpt ?? process.env[registry.addressEnvKey];
410
+ if (!contractAddress) {
411
+ throw new Error(
412
+ `No contract address for "${registryName}". ` +
413
+ `Provide --to <address> or set ${registry.addressEnvKey}.`,
414
+ );
415
+ }
416
+
417
+ const wallet = await resolveWallet(opts, config);
418
+
419
+ // Resolve access token. With --auto-token and no explicit --scope, the
420
+ // default scope targets the same instance being written to
421
+ // (`contractAddress`), so the minted token is authorised against
422
+ // exactly that beacon-proxy instance.
423
+ const token = await resolveWriteToken(
424
+ opts,
425
+ config,
426
+ wallet,
427
+ `${defaultScopeFor(registryName, functionName, registry)}:${contractAddress}`,
428
+ );
429
+
430
+ const gas = parseGasOverrides(opts);
431
+ const receipt = await writeToRegistry({
432
+ config,
433
+ contractAddress,
434
+ functionArgs,
435
+ functionName,
436
+ ...(gas !== undefined && { gas }),
437
+ registry,
438
+ token,
439
+ wallet,
440
+ });
441
+
442
+ return receipt;
443
+ },
444
+ id: "ledger.write",
445
+ options: [
446
+ {
447
+ description:
448
+ "Contract address (0x-prefixed). If omitted, read from the corresponding env var " +
449
+ "(e.g. DID_REGISTRY_CONTRACT_ADDRESS for did-registry).",
450
+ flags: "--to <address>",
451
+ },
452
+ {
453
+ description:
454
+ "Obtain a fresh access token automatically using the VP flow " +
455
+ "before submitting the transaction. Uses the registry/function's default scope " +
456
+ '(e.g. "did-registry:invite" for did-registry insertDidDocument, "track-and-trace:authorise" for ' +
457
+ 'track-and-trace authoriseDid, "track-and-trace:create" for track-and-trace createDocument/' +
458
+ "commitCreateDocument, and each registry's plain write scope for every other " +
459
+ "function), targeted at the resolved --to contract instance, unless --scope " +
460
+ "overrides it.",
461
+ flags: "--auto-token",
462
+ },
463
+ {
464
+ description:
465
+ "EBSI scope to use when requesting a token with --auto-token " +
466
+ '(e.g. "did-registry:write", "issuers-registry:invite", or "track-and-trace:write:0x61c3..." to target a specific ' +
467
+ "instance). Defaults to the registry/function's default scope targeted at --to.",
468
+ flags: "--scope <scope>",
469
+ },
470
+ {
471
+ description:
472
+ "Path to a VC JWT file. Required for VC-required scopes " +
473
+ "(did-registry:invite, ledger:invoke, issuers-registry:invite, track-and-trace:authorise) when using --auto-token.",
474
+ flags: "--vc <file>",
475
+ },
476
+ ...WALLET_KEY_OPTIONS,
477
+ {
478
+ description: "EBSI DID to use. Overrides config/env.",
479
+ flags: "--did <did>",
480
+ },
481
+ {
482
+ description:
483
+ "Advanced: manual gas limit (decimal or 0x-prefixed hex), overriding the " +
484
+ "eth_estimateGas result. By default the gas limit is estimated dynamically from the node.",
485
+ flags: "--gas-limit <value>",
486
+ },
487
+ {
488
+ description:
489
+ "Advanced: manual gas price (decimal or 0x-prefixed hex), forcing a legacy " +
490
+ "transaction. By default fees are derived dynamically from the node (EIP-1559 when supported).",
491
+ flags: "--gas-price <value>",
492
+ },
493
+ ],
494
+ segments: ["ledger", "write"],
495
+ summary:
496
+ "ABI-encode a registry function call, sign an Ethereum transaction, and submit it " +
497
+ "via POST /ledger. " +
498
+ "Requires a private key and an access token (or --auto-token to mint one inline). " +
499
+ "Contract address comes from --to or the corresponding env var " +
500
+ "(e.g. DID_REGISTRY_CONTRACT_ADDRESS). " +
501
+ "Known registries: " +
502
+ REGISTRY_NAMES.join(", ") +
503
+ ".",
504
+ },
505
+
506
+ {
507
+ args: [
508
+ {
509
+ description: "Registry name: " + REGISTRY_NAMES.join(", "),
510
+ example: "timestamp",
511
+ name: "registry",
512
+ required: true,
513
+ },
514
+ {
515
+ description:
516
+ "Smart-contract view/pure function to call (e.g. getTimestamp, computeTimestampCommitment)",
517
+ example: "computeTimestampCommitment",
518
+ name: "function",
519
+ required: true,
520
+ },
521
+ {
522
+ description:
523
+ "Function arguments as a JSON array string (e.g. '[\"0x1234\"]'). " +
524
+ "Types must match the contract ABI exactly.",
525
+ example: '["0xCommitter", [1], ["0xhash"], [], "0xsalt"]',
526
+ name: "args",
527
+ required: true,
528
+ },
529
+ ],
530
+ group: "Ledger",
531
+ async handler(args, opts, config) {
532
+ const registryName = requiredArg(args, "registry");
533
+ const functionName = requiredArg(args, "function");
534
+ const functionArgs = parseJsonArray(requiredArg(args, "args"), "args");
535
+
536
+ const registry = REGISTRIES[registryName];
537
+ if (!registry) {
538
+ throw new Error(
539
+ `Unknown registry "${registryName}". Known registries: ${REGISTRY_NAMES.join(", ")}`,
540
+ );
541
+ }
542
+
543
+ // Resolve contract address: --to → env var → error
544
+ const toOpt = opts["to"];
545
+ const contractAddress = toOpt ?? process.env[registry.addressEnvKey];
546
+ if (!contractAddress) {
547
+ throw new Error(
548
+ `No contract address for "${registryName}". ` +
549
+ `Provide --to <address> or set ${registry.addressEnvKey}.`,
550
+ );
551
+ }
552
+
553
+ return readFromRegistry({
554
+ config,
555
+ contractAddress,
556
+ functionArgs,
557
+ functionName,
558
+ registry,
559
+ });
560
+ },
561
+ id: "ledger.read",
562
+ options: [
563
+ {
564
+ description:
565
+ "Contract address (0x-prefixed). If omitted, read from the corresponding env var " +
566
+ "(e.g. TIMESTAMP_CONTRACT_ADDRESS for timestamp).",
567
+ flags: "--to <address>",
568
+ },
569
+ ],
570
+ segments: ["ledger", "read"],
571
+ summary:
572
+ "ABI-encode a registry view/pure function call and resolve it via eth_call — " +
573
+ "the read-only counterpart to `ledger write`. No wallet or token needed, since " +
574
+ "eth_call is served anonymously. Returns the function's outputs as an array, " +
575
+ "in declaration order. Contract address comes from --to or the corresponding " +
576
+ "env var. Known registries: " +
577
+ REGISTRY_NAMES.join(", ") +
578
+ ".",
579
+ },
580
+
581
+ {
582
+ args: [
583
+ {
584
+ description:
585
+ "Path to a JSON file containing a JSON array of JSON-RPC requests, or '-' to read from stdin. " +
586
+ 'Each entry needs a "method" field; "params" defaults to [] and "id" may be omitted to send ' +
587
+ "a notification (no response entry for that request).",
588
+ example: "./batch.json",
589
+ name: "source",
590
+ required: true,
591
+ },
592
+ ],
593
+ group: "Ledger",
594
+ async handler(args, _opts, config) {
595
+ const source = requiredArg(args, "source");
596
+ const raw =
597
+ source === "-" ? await readStdin() : readFileSync(source, "utf8");
598
+
599
+ let parsed: unknown;
600
+ try {
601
+ parsed = JSON.parse(raw);
602
+ } catch (error) {
603
+ /* v8 ignore next -- JSON.parse only ever throws a real Error/SyntaxError */
604
+ const message = error instanceof Error ? error.message : "parse error";
605
+ throw new Error(`Invalid JSON in "${source}": ${message}`, {
606
+ cause: error,
607
+ });
608
+ }
609
+ if (!Array.isArray(parsed) || parsed.length === 0) {
610
+ throw new Error(
611
+ "Batch source must contain a non-empty JSON array of JSON-RPC requests.",
612
+ );
613
+ }
614
+
615
+ const batch = parsed.map((entry, index) =>
616
+ normalizeBatchEntry(entry, index),
617
+ );
618
+
619
+ const client = getClient(config);
620
+ const result = await client.POST("/ledger", {
621
+ body: batch as unknown as JsonRpcBatchPayload,
622
+ });
623
+ return unwrap(result);
624
+ },
625
+ id: "ledger.batch",
626
+ options: [],
627
+ segments: ["ledger", "batch"],
628
+ summary:
629
+ "Send a JSON-RPC batch request to the Besu node via POST /ledger — an array of independent " +
630
+ "requests processed in order under a single Authorization header (--token, EBSI_ACCESS_TOKEN, " +
631
+ "or `ebsi config set token`). Besu accepts at most 1024 requests per batch. Useful for grouping " +
632
+ "reads, or submitting several pre-signed raw transactions (eth_sendRawTransaction) together. " +
633
+ "For signing and submitting several registry writes in one batch, use `ledger write-batch`.",
634
+ },
635
+
636
+ {
637
+ args: [
638
+ {
639
+ description:
640
+ 'Path to a JSON file containing a JSON array of write entries: {"registry", "function", ' +
641
+ '"args", "to"?} — same shape as the `ledger write` positional args. "to" falls back to the ' +
642
+ "registry's env var, per entry, if omitted.",
643
+ example: "./writes.json",
644
+ name: "file",
645
+ required: true,
646
+ },
647
+ ],
648
+ group: "Ledger",
649
+ async handler(args, opts, config) {
650
+ const file = requiredArg(args, "file");
651
+ const fileEntries = parseWriteBatchFile(readFileSync(file, "utf8"));
652
+
653
+ // Resolve each entry's registry + contract address up front, so a bad
654
+ // entry fails before any signing/network activity happens.
655
+ const resolvedEntries = fileEntries.map((entry, index) => {
656
+ const position = `Entry #${(index + 1).toString()}`;
657
+ const registry = REGISTRIES[entry.registry];
658
+ if (!registry) {
659
+ throw new Error(
660
+ `${position}: unknown registry "${entry.registry}". Known registries: ${REGISTRY_NAMES.join(", ")}`,
661
+ );
662
+ }
663
+ const to = entry.to ?? process.env[registry.addressEnvKey];
664
+ if (!to) {
665
+ throw new Error(
666
+ `${position}: no contract address for "${entry.registry}". ` +
667
+ `Set "to" in the batch file or the ${registry.addressEnvKey} env var.`,
668
+ );
669
+ }
670
+ return {
671
+ functionArgs: entry.args,
672
+ functionName: entry.function,
673
+ registry,
674
+ registryName: entry.registry,
675
+ to,
676
+ };
677
+ });
678
+
679
+ const wallet = await resolveWallet(opts, config);
680
+
681
+ // Resolve access token — with --auto-token and no explicit --scope, derive
682
+ // the minimal multi-scope token covering every distinct registry in the
683
+ // batch, each instance-targeted at the address it's being written to.
684
+ const defaultScope = deriveScopeForRegistries(
685
+ resolvedEntries.map(({ functionName, registryName, to }) => ({
686
+ functionName,
687
+ registryName,
688
+ to,
689
+ })),
690
+ );
691
+ const token = await resolveWriteToken(opts, config, wallet, defaultScope);
692
+
693
+ // Sign every write against one nonce sequence, then submit as one batch
694
+ const gas = parseGasOverrides(opts);
695
+ const rawTxs = await signWriteBatch({
696
+ config,
697
+ entries: resolvedEntries.map(
698
+ ({ functionArgs, functionName, registry, to }) => ({
699
+ functionArgs,
700
+ functionName,
701
+ registry,
702
+ to,
703
+ }),
704
+ ),
705
+ ...(gas !== undefined && { gas }),
706
+ token,
707
+ wallet,
708
+ });
709
+
710
+ const batchBody = rawTxs.map((rawTx, index) => ({
711
+ id: index + 1,
712
+ jsonrpc: "2.0" as const,
713
+ method: "eth_sendRawTransaction",
714
+ params: [rawTx],
715
+ }));
716
+
717
+ const client = getClient(config);
718
+ const result = await client.POST("/ledger", {
719
+ body: batchBody,
720
+ });
721
+ return unwrap(result);
722
+ },
723
+ id: "ledger.write-batch",
724
+ options: [
725
+ {
726
+ description:
727
+ "Obtain a fresh access token automatically using the VP flow before submitting the batch. " +
728
+ "Uses the minimal multi-scope token covering every distinct registry in the batch, each " +
729
+ "targeted at the instance it's being written to, unless --scope overrides it.",
730
+ flags: "--auto-token",
731
+ },
732
+ {
733
+ description:
734
+ 'EBSI scope to use when requesting a token with --auto-token (e.g. "did-registry:write issuers-registry:write"). ' +
735
+ "Defaults to the minimal multi-scope combination derived from the batch's registries, " +
736
+ "each instance-targeted at its resolved contract address.",
737
+ flags: "--scope <scope>",
738
+ },
739
+ {
740
+ description:
741
+ "Path to a VC JWT file. Only relevant if --scope is overridden to a VC-required scope " +
742
+ "(uncommon for a multi-write batch).",
743
+ flags: "--vc <file>",
744
+ },
745
+ ...WALLET_KEY_OPTIONS,
746
+ {
747
+ description: "EBSI DID to use. Overrides config/env.",
748
+ flags: "--did <did>",
749
+ },
750
+ {
751
+ description:
752
+ "Advanced: manual gas limit (decimal or 0x-prefixed hex), shared by every entry, " +
753
+ "overriding the eth_estimateGas result. By default the gas limit is estimated dynamically, " +
754
+ "per entry, from the node.",
755
+ flags: "--gas-limit <value>",
756
+ },
757
+ {
758
+ description:
759
+ "Advanced: manual gas price (decimal or 0x-prefixed hex), shared by every entry, " +
760
+ "forcing legacy transactions. By default fees are derived dynamically from the node " +
761
+ "(EIP-1559 when supported).",
762
+ flags: "--gas-price <value>",
763
+ },
764
+ ],
765
+ segments: ["ledger", "write-batch"],
766
+ summary:
767
+ "Sign several registry writes from one wallet, under one access token, and submit them as a " +
768
+ "single JSON-RPC batch request via POST /ledger — one round-trip instead of one per write. " +
769
+ "Each write gets a sequential nonce so they don't collide. With --auto-token, one multi-scope " +
770
+ "token is minted covering every distinct registry referenced in the batch file " +
771
+ "(combinable scopes only: did-registry:write, issuers-registry:write, timestamp:write, track-and-trace:create, track-and-trace:write, " +
772
+ "policies-registry:write, schemas-registry:write). Returns transaction hashes, not receipts — use `ledger tx <hash>` " +
773
+ "to check status afterwards. Known registries: " +
774
+ REGISTRY_NAMES.join(", ") +
775
+ ".",
776
+ },
777
+ ];